mirror of
https://github.com/MidnightCommander/mc
synced 2024-12-23 04:46:55 +03:00
1573 lines
40 KiB
C
1573 lines
40 KiB
C
/* editor syntax highlighting.
|
||
|
||
Copyright (C) 1996, 1997, 1998 the Free Software Foundation
|
||
|
||
Authors: 1998 Paul Sheer
|
||
|
||
$Id$
|
||
|
||
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.
|
||
*/
|
||
|
||
#include <config.h>
|
||
#if defined(MIDNIGHT) || defined(GTK)
|
||
#include "edit.h"
|
||
#else
|
||
#include "coolwidget.h"
|
||
#endif
|
||
#if defined (HAVE_MAD) && ! defined (MIDNIGHT) && ! defined (GTK)
|
||
#include "mad.h"
|
||
#endif
|
||
|
||
/* bytes */
|
||
#define SYNTAX_MARKER_DENSITY 512
|
||
|
||
/*
|
||
Mispelled words are flushed from the syntax highlighting rules
|
||
when they have been around longer than
|
||
TRANSIENT_WORD_TIME_OUT seconds. At a cursor rate of 30
|
||
chars per second and say 3 chars + a space per word, we can
|
||
accumulate 450 words absolute max with a value of 60. This is
|
||
below this limit of 1024 words in a context.
|
||
*/
|
||
#define TRANSIENT_WORD_TIME_OUT 60
|
||
|
||
#define UNKNOWN_FORMAT "unknown"
|
||
|
||
#if !defined(MIDNIGHT) || defined(HAVE_SYNTAXH)
|
||
|
||
int option_syntax_highlighting = 1;
|
||
int option_auto_spellcheck = 1;
|
||
|
||
/* these three functions are called from the outside */
|
||
void edit_load_syntax (WEdit * edit, char **names, char *type);
|
||
void edit_free_syntax_rules (WEdit * edit);
|
||
void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg);
|
||
|
||
#ifdef HAVE_MAD
|
||
static void *mad_syntax_malloc (size_t x, char *file, int line)
|
||
#define syntax_malloc(x) mad_syntax_malloc (x, __FILE__, __LINE__)
|
||
#else
|
||
static void *syntax_malloc (size_t x)
|
||
#endif
|
||
{
|
||
void *p;
|
||
#ifdef HAVE_MAD
|
||
p = mad_alloc (x, file, line);
|
||
#else
|
||
p = malloc (x);
|
||
#endif
|
||
memset (p, 0, x);
|
||
return p;
|
||
}
|
||
|
||
#define syntax_free(x) {if(x){free(x);(x)=0;}}
|
||
|
||
static long compare_word_to_right (WEdit * edit, long i, char *text, char *whole_left, char *whole_right, int line_start)
|
||
{
|
||
unsigned char *p, *q;
|
||
int c, d, j;
|
||
if (!*text)
|
||
return -1;
|
||
c = edit_get_byte (edit, i - 1);
|
||
if (line_start)
|
||
if (c != '\n')
|
||
return -1;
|
||
if (whole_left)
|
||
if (strchr (whole_left, c))
|
||
return -1;
|
||
for (p = (unsigned char *) text, q = p + strlen ((char *) p); (unsigned long) p < (unsigned long) q; p++, i++) {
|
||
switch (*p) {
|
||
case '\001':
|
||
p++;
|
||
for (;;) {
|
||
c = edit_get_byte (edit, i);
|
||
if (!*p)
|
||
if (whole_right)
|
||
if (!strchr (whole_right, c))
|
||
break;
|
||
if (c == *p)
|
||
break;
|
||
if (c == '\n')
|
||
return -1;
|
||
i++;
|
||
}
|
||
break;
|
||
case '\002':
|
||
p++;
|
||
j = 0;
|
||
for (;;) {
|
||
c = edit_get_byte (edit, i);
|
||
if (c == *p) {
|
||
j = i;
|
||
if (*p == *text && !p[1]) /* handle eg '+' and @+@ keywords properly */
|
||
break;
|
||
}
|
||
if (j && strchr ((char *) p + 1, c)) /* c exists further down, so it will get matched later */
|
||
break;
|
||
if (c == '\n' || c == '\t' || c == ' ') {
|
||
if (!*p) {
|
||
i--;
|
||
break;
|
||
}
|
||
if (!j)
|
||
return -1;
|
||
i = j;
|
||
break;
|
||
}
|
||
if (whole_right)
|
||
if (!strchr (whole_right, c)) {
|
||
if (!*p) {
|
||
i--;
|
||
break;
|
||
}
|
||
if (!j)
|
||
return -1;
|
||
i = j;
|
||
break;
|
||
}
|
||
i++;
|
||
}
|
||
break;
|
||
case '\003':
|
||
p++;
|
||
c = -1;
|
||
for (;; i++) {
|
||
d = c;
|
||
c = edit_get_byte (edit, i);
|
||
for (j = 0; p[j] != '\003'; j++)
|
||
if (c == p[j])
|
||
goto found_char2;
|
||
break;
|
||
found_char2:
|
||
j = c; /* dummy command */
|
||
}
|
||
i--;
|
||
while (*p != '\003')
|
||
p++;
|
||
if (p[1] == d)
|
||
i--;
|
||
break;
|
||
case '\004':
|
||
p++;
|
||
c = edit_get_byte (edit, i);
|
||
for (; *p != '\004'; p++)
|
||
if (c == *p)
|
||
goto found_char3;
|
||
return -1;
|
||
found_char3:
|
||
for (; *p != '\004'; p++);
|
||
break;
|
||
default:
|
||
if (*p != edit_get_byte (edit, i))
|
||
return -1;
|
||
}
|
||
}
|
||
if (whole_right)
|
||
if (strchr (whole_right, edit_get_byte (edit, i)))
|
||
return -1;
|
||
return i;
|
||
}
|
||
|
||
#define XXX \
|
||
if (*s < '\005' || *s == (unsigned char) c) \
|
||
goto done; \
|
||
s++;
|
||
|
||
static inline char *xx_strchr (const unsigned char *s, int c)
|
||
{
|
||
repeat:
|
||
XXX XXX XXX XXX XXX XXX XXX XXX;
|
||
XXX XXX XXX XXX XXX XXX XXX XXX;
|
||
goto repeat;
|
||
done:
|
||
return (char *) s;
|
||
}
|
||
|
||
static inline struct syntax_rule apply_rules_going_right (WEdit * edit, long i, struct syntax_rule rule)
|
||
{
|
||
struct context_rule *r;
|
||
int contextchanged = 0, c;
|
||
int found_right = 0, found_left = 0, keyword_foundleft = 0, keyword_foundright = 0;
|
||
int is_end;
|
||
long end = 0;
|
||
struct syntax_rule _rule = rule;
|
||
if (!(c = edit_get_byte (edit, i)))
|
||
return rule;
|
||
is_end = (rule.end == (unsigned char) i);
|
||
/* check to turn off a keyword */
|
||
if (_rule.keyword) {
|
||
struct key_word *k;
|
||
k = edit->rules[_rule.context]->keyword[_rule.keyword];
|
||
if (edit_get_byte (edit, i - 1) == '\n')
|
||
_rule.keyword = 0;
|
||
if (is_end) {
|
||
_rule.keyword = 0;
|
||
keyword_foundleft = 1;
|
||
}
|
||
}
|
||
/* check to turn off a context */
|
||
if (_rule.context && !_rule.keyword) {
|
||
long e;
|
||
r = edit->rules[_rule.context];
|
||
if (r->first_right == c && !(rule.border & RULE_ON_RIGHT_BORDER) && (e = compare_word_to_right (edit, i, r->right, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_right)) > 0) {
|
||
_rule.end = e;
|
||
found_right = 1;
|
||
_rule.border = RULE_ON_RIGHT_BORDER;
|
||
if (r->between_delimiters)
|
||
_rule.context = 0;
|
||
} else if (is_end && rule.border & RULE_ON_RIGHT_BORDER) {
|
||
/* always turn off a context at 4 */
|
||
found_left = 1;
|
||
_rule.border = 0;
|
||
if (!keyword_foundleft)
|
||
_rule.context = 0;
|
||
} else if (is_end && rule.border & RULE_ON_LEFT_BORDER) {
|
||
/* never turn off a context at 2 */
|
||
found_left = 1;
|
||
_rule.border = 0;
|
||
}
|
||
}
|
||
/* check to turn on a keyword */
|
||
if (!_rule.keyword) {
|
||
char *p;
|
||
p = (r = edit->rules[_rule.context])->keyword_first_chars;
|
||
while (*(p = xx_strchr ((unsigned char *) p + 1, c))) {
|
||
struct key_word *k;
|
||
int count;
|
||
long e;
|
||
count = (unsigned long) p - (unsigned long) r->keyword_first_chars;
|
||
k = r->keyword[count];
|
||
e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start);
|
||
if (e > 0) {
|
||
end = e;
|
||
_rule.end = e;
|
||
_rule.keyword = count;
|
||
keyword_foundright = 1;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
/* check to turn on a context */
|
||
if (!_rule.context) {
|
||
if (!found_left && is_end) {
|
||
if (rule.border & RULE_ON_RIGHT_BORDER) {
|
||
_rule.border = 0;
|
||
_rule.context = 0;
|
||
contextchanged = 1;
|
||
_rule.keyword = 0;
|
||
} else if (rule.border & RULE_ON_LEFT_BORDER) {
|
||
r = edit->rules[_rule._context];
|
||
_rule.border = 0;
|
||
if (r->between_delimiters) {
|
||
long e;
|
||
_rule.context = _rule._context;
|
||
contextchanged = 1;
|
||
_rule.keyword = 0;
|
||
if (r->first_right == c && (e = compare_word_to_right (edit, i, r->right, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_right)) >= end) {
|
||
_rule.end = e;
|
||
found_right = 1;
|
||
_rule.border = RULE_ON_RIGHT_BORDER;
|
||
_rule.context = 0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (!found_right) {
|
||
int count;
|
||
struct context_rule **rules = edit->rules;
|
||
for (count = 1; rules[count]; count++) {
|
||
r = rules[count];
|
||
if (r->first_left == c) {
|
||
long e;
|
||
e = compare_word_to_right (edit, i, r->left, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_left);
|
||
if (e >= end && (!_rule.keyword || keyword_foundright)) {
|
||
_rule.end = e;
|
||
found_right = 1;
|
||
_rule.border = RULE_ON_LEFT_BORDER;
|
||
_rule._context = count;
|
||
if (!r->between_delimiters)
|
||
if (!_rule.keyword)
|
||
_rule.context = count;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
/* check again to turn on a keyword if the context switched */
|
||
if (contextchanged && !_rule.keyword) {
|
||
char *p;
|
||
p = (r = edit->rules[_rule.context])->keyword_first_chars;
|
||
while (*(p = xx_strchr ((unsigned char *) p + 1, c))) {
|
||
struct key_word *k;
|
||
int count;
|
||
long e;
|
||
count = (unsigned long) p - (unsigned long) r->keyword_first_chars;
|
||
k = r->keyword[count];
|
||
e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start);
|
||
if (e > 0) {
|
||
_rule.end = e;
|
||
_rule.keyword = count;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
return _rule;
|
||
}
|
||
|
||
static struct syntax_rule edit_get_rule (WEdit * edit, long byte_index)
|
||
{
|
||
long i;
|
||
if (byte_index > edit->last_get_rule) {
|
||
for (i = edit->last_get_rule + 1; i <= byte_index; i++) {
|
||
edit->rule = apply_rules_going_right (edit, i, edit->rule);
|
||
if (i > (edit->syntax_marker ? edit->syntax_marker->offset + SYNTAX_MARKER_DENSITY : SYNTAX_MARKER_DENSITY)) {
|
||
struct _syntax_marker *s;
|
||
s = edit->syntax_marker;
|
||
edit->syntax_marker = syntax_malloc (sizeof (struct _syntax_marker));
|
||
edit->syntax_marker->next = s;
|
||
edit->syntax_marker->offset = i;
|
||
edit->syntax_marker->rule = edit->rule;
|
||
}
|
||
}
|
||
} else if (byte_index < edit->last_get_rule) {
|
||
struct _syntax_marker *s;
|
||
for (;;) {
|
||
if (!edit->syntax_marker) {
|
||
memset (&edit->rule, 0, sizeof (edit->rule));
|
||
for (i = -1; i <= byte_index; i++)
|
||
edit->rule = apply_rules_going_right (edit, i, edit->rule);
|
||
break;
|
||
}
|
||
if (byte_index >= edit->syntax_marker->offset) {
|
||
edit->rule = edit->syntax_marker->rule;
|
||
for (i = edit->syntax_marker->offset + 1; i <= byte_index; i++)
|
||
edit->rule = apply_rules_going_right (edit, i, edit->rule);
|
||
break;
|
||
}
|
||
s = edit->syntax_marker->next;
|
||
syntax_free (edit->syntax_marker);
|
||
edit->syntax_marker = s;
|
||
}
|
||
}
|
||
edit->last_get_rule = byte_index;
|
||
return edit->rule;
|
||
}
|
||
|
||
static void translate_rule_to_color (WEdit * edit, struct syntax_rule rule, int *fg, int *bg)
|
||
{
|
||
struct key_word *k;
|
||
k = edit->rules[rule.context]->keyword[rule.keyword];
|
||
*bg = k->bg;
|
||
*fg = k->fg;
|
||
}
|
||
|
||
extern int use_colors;
|
||
|
||
void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg)
|
||
{
|
||
if (edit->rules && byte_index < edit->last_byte &&
|
||
option_syntax_highlighting && use_colors) {
|
||
translate_rule_to_color (edit, edit_get_rule (edit, byte_index), fg, bg);
|
||
} else {
|
||
#ifdef MIDNIGHT
|
||
*fg = EDITOR_NORMAL_COLOR;
|
||
#else
|
||
*fg = NO_COLOR;
|
||
*bg = NO_COLOR;
|
||
#endif
|
||
}
|
||
}
|
||
|
||
|
||
/*
|
||
Returns 0 on error/eof or a count of the number of bytes read
|
||
including the newline. Result must be free'd.
|
||
*/
|
||
#ifdef HAVE_MAD
|
||
static int mad_read_one_line (char **line, FILE * f, char *file, int line_)
|
||
#define read_one_line(a,b) mad_read_one_line(a,b,__FILE__,__LINE__)
|
||
#else
|
||
static int read_one_line (char **line, FILE * f)
|
||
#endif
|
||
{
|
||
char *p;
|
||
int len = 256, c, r = 0, i = 0;
|
||
#ifdef HAVE_MAD
|
||
p = mad_syntax_malloc (len, file, line_);
|
||
#else
|
||
p = syntax_malloc (len);
|
||
#endif
|
||
for (;;) {
|
||
c = fgetc (f);
|
||
if (c == -1) {
|
||
if (errno == EINTR)
|
||
continue;
|
||
r = 0;
|
||
break;
|
||
} else if (c == '\n') {
|
||
r = i + 1; /* extra 1 for the newline just read */
|
||
break;
|
||
} else {
|
||
if (i >= len - 1) {
|
||
char *q;
|
||
q = syntax_malloc (len * 2);
|
||
memcpy (q, p, len);
|
||
syntax_free (p);
|
||
p = q;
|
||
len *= 2;
|
||
}
|
||
p[i++] = c;
|
||
}
|
||
}
|
||
p[i] = 0;
|
||
*line = p;
|
||
return r;
|
||
}
|
||
|
||
static char *strdup_convert (char *s)
|
||
{
|
||
char *r, *p;
|
||
p = r = (char *) strdup (s);
|
||
while (*s) {
|
||
switch (*s) {
|
||
case '\\':
|
||
s++;
|
||
switch (*s) {
|
||
case ' ':
|
||
*p = ' ';
|
||
s--;
|
||
break;
|
||
case 'n':
|
||
*p = '\n';
|
||
break;
|
||
case 'r':
|
||
*p = '\r';
|
||
break;
|
||
case 't':
|
||
*p = '\t';
|
||
break;
|
||
case 's':
|
||
*p = ' ';
|
||
break;
|
||
case '*':
|
||
*p = '*';
|
||
break;
|
||
case '\\':
|
||
*p = '\\';
|
||
break;
|
||
case '[':
|
||
case ']':
|
||
*p = '\003';
|
||
break;
|
||
case '{':
|
||
case '}':
|
||
*p = '\004';
|
||
break;
|
||
default:
|
||
*p = *s;
|
||
break;
|
||
}
|
||
break;
|
||
case '*':
|
||
*p = '\001';
|
||
break;
|
||
case '+':
|
||
*p = '\002';
|
||
break;
|
||
default:
|
||
*p = *s;
|
||
break;
|
||
}
|
||
s++;
|
||
p++;
|
||
}
|
||
*p = '\0';
|
||
return r;
|
||
}
|
||
|
||
#define whiteness(x) ((x) == '\t' || (x) == '\n' || (x) == ' ')
|
||
|
||
static void get_args (char *l, char **args, int *argc)
|
||
{
|
||
*argc = 0;
|
||
l--;
|
||
for (;;) {
|
||
char *p;
|
||
for (p = l + 1; *p && whiteness (*p); p++);
|
||
if (!*p)
|
||
break;
|
||
for (l = p + 1; *l && !whiteness (*l); l++);
|
||
*l = '\0';
|
||
*args = strdup_convert (p);
|
||
(*argc)++;
|
||
args++;
|
||
}
|
||
*args = 0;
|
||
}
|
||
|
||
static void free_args (char **args)
|
||
{
|
||
while (*args) {
|
||
syntax_free (*args);
|
||
*args = 0;
|
||
args++;
|
||
}
|
||
}
|
||
|
||
#define check_a {if(!*a){result=line;break;}}
|
||
#define check_not_a {if(*a){result=line;break;}}
|
||
|
||
#ifdef MIDNIGHT
|
||
|
||
int try_alloc_color_pair (char *fg, char *bg);
|
||
|
||
int this_try_alloc_color_pair (char *fg, char *bg)
|
||
{
|
||
char f[80], b[80], *p;
|
||
if (bg)
|
||
if (!*bg)
|
||
bg = 0;
|
||
if (fg)
|
||
if (!*fg)
|
||
fg = 0;
|
||
if (fg) {
|
||
strcpy (f, fg);
|
||
p = strchr (f, '/');
|
||
if (p)
|
||
*p = '\0';
|
||
fg = f;
|
||
}
|
||
if (bg) {
|
||
strcpy (b, bg);
|
||
p = strchr (b, '/');
|
||
if (p)
|
||
*p = '\0';
|
||
bg = b;
|
||
}
|
||
return try_alloc_color_pair (fg, bg);
|
||
}
|
||
#else
|
||
#ifdef GTK
|
||
int allocate_color (WEdit *edit, gchar *color);
|
||
|
||
int this_allocate_color (WEdit *edit, char *fg)
|
||
{
|
||
char *p;
|
||
if (fg)
|
||
if (!*fg)
|
||
fg = 0;
|
||
if (!fg)
|
||
return allocate_color (edit, 0);
|
||
p = strchr (fg, '/');
|
||
if (!p)
|
||
return allocate_color (edit, fg);
|
||
return allocate_color (edit, p + 1);
|
||
}
|
||
#else
|
||
int this_allocate_color (WEdit *edit, char *fg)
|
||
{
|
||
char *p;
|
||
if (fg)
|
||
if (!*fg)
|
||
fg = 0;
|
||
if (!fg)
|
||
return allocate_color (0);
|
||
p = strchr (fg, '/');
|
||
if (!p)
|
||
return allocate_color (fg);
|
||
return allocate_color (p + 1);
|
||
}
|
||
#endif /* GTK */
|
||
#endif /* MIDNIGHT */
|
||
|
||
static char *error_file_name = 0;
|
||
|
||
extern char *mc_home;
|
||
|
||
static FILE *open_include_file (char *filename)
|
||
{
|
||
FILE *f;
|
||
char p[MAX_PATH_LEN];
|
||
syntax_free (error_file_name);
|
||
error_file_name = (char *) strdup (filename);
|
||
if (*filename == '/')
|
||
return fopen (filename, "r");
|
||
strcpy (p, home_dir);
|
||
strcat (p, EDIT_DIR "/");
|
||
strcat (p, filename);
|
||
syntax_free (error_file_name);
|
||
error_file_name = (char *) strdup (p);
|
||
f = fopen (p, "r");
|
||
if (f)
|
||
return f;
|
||
#if !defined (MIDNIGHT) && !defined(GTK)
|
||
strcpy (p, LIBDIR "/syntax/");
|
||
#else
|
||
strcpy (p, mc_home);
|
||
strcat (p, "/syntax/");
|
||
#endif /* MIDNIGHT || GTK */
|
||
strcat (p, filename);
|
||
syntax_free (error_file_name);
|
||
error_file_name = (char *) strdup (p);
|
||
return fopen (p, "r");
|
||
}
|
||
|
||
/* returns line number on error */
|
||
static int edit_read_syntax_rules (WEdit * edit, FILE * f)
|
||
{
|
||
FILE *g = 0;
|
||
char *fg, *bg;
|
||
char last_fg[32] = "", last_bg[32] = "";
|
||
char whole_right[512];
|
||
char whole_left[512];
|
||
char *args[1024], *l = 0;
|
||
int save_line = 0, line = 0;
|
||
struct context_rule **r, *c = 0;
|
||
int num_words = -1, num_contexts = -1;
|
||
int argc, result = 0;
|
||
int i, j;
|
||
|
||
args[0] = 0;
|
||
|
||
strcpy (whole_left, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
|
||
strcpy (whole_right, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
|
||
|
||
r = edit->rules = syntax_malloc (MAX_CONTEXTS * sizeof (struct context_rule *));
|
||
|
||
for (;;) {
|
||
char **a;
|
||
line++;
|
||
l = 0;
|
||
if (!read_one_line (&l, f)) {
|
||
if (g) {
|
||
fclose (f);
|
||
f = g;
|
||
g = 0;
|
||
line = save_line + 1;
|
||
syntax_free (error_file_name);
|
||
if (l)
|
||
syntax_free (l);
|
||
if (!read_one_line (&l, f))
|
||
break;
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
get_args (l, args, &argc);
|
||
a = args + 1;
|
||
if (!args[0]) {
|
||
/* do nothing */
|
||
} else if (!strcmp (args[0], "include")) {
|
||
if (g || argc != 2) {
|
||
result = line;
|
||
break;
|
||
}
|
||
g = f;
|
||
f = open_include_file (args[1]);
|
||
if (!f) {
|
||
syntax_free (error_file_name);
|
||
result = line;
|
||
break;
|
||
}
|
||
save_line = line;
|
||
line = 0;
|
||
} else if (!strcmp (args[0], "wholechars")) {
|
||
check_a;
|
||
if (!strcmp (*a, "left")) {
|
||
a++;
|
||
strcpy (whole_left, *a);
|
||
} else if (!strcmp (*a, "right")) {
|
||
a++;
|
||
strcpy (whole_right, *a);
|
||
} else {
|
||
strcpy (whole_left, *a);
|
||
strcpy (whole_right, *a);
|
||
}
|
||
a++;
|
||
check_not_a;
|
||
} else if (!strcmp (args[0], "context")) {
|
||
check_a;
|
||
if (num_contexts == -1) {
|
||
if (strcmp (*a, "default")) { /* first context is the default */
|
||
*a = 0;
|
||
check_a;
|
||
}
|
||
a++;
|
||
c = r[0] = syntax_malloc (sizeof (struct context_rule));
|
||
c->left = (char *) strdup (" ");
|
||
c->right = (char *) strdup (" ");
|
||
num_contexts = 0;
|
||
} else {
|
||
c = r[num_contexts] = syntax_malloc (sizeof (struct context_rule));
|
||
if (!strcmp (*a, "exclusive")) {
|
||
a++;
|
||
c->between_delimiters = 1;
|
||
}
|
||
check_a;
|
||
if (!strcmp (*a, "whole")) {
|
||
a++;
|
||
c->whole_word_chars_left = (char *) strdup (whole_left);
|
||
c->whole_word_chars_right = (char *) strdup (whole_right);
|
||
} else if (!strcmp (*a, "wholeleft")) {
|
||
a++;
|
||
c->whole_word_chars_left = (char *) strdup (whole_left);
|
||
} else if (!strcmp (*a, "wholeright")) {
|
||
a++;
|
||
c->whole_word_chars_right = (char *) strdup (whole_right);
|
||
}
|
||
check_a;
|
||
if (!strcmp (*a, "linestart")) {
|
||
a++;
|
||
c->line_start_left = 1;
|
||
}
|
||
check_a;
|
||
c->left = (char *) strdup (*a++);
|
||
check_a;
|
||
if (!strcmp (*a, "linestart")) {
|
||
a++;
|
||
c->line_start_right = 1;
|
||
}
|
||
check_a;
|
||
c->right = (char *) strdup (*a++);
|
||
c->first_left = *c->left;
|
||
c->first_right = *c->right;
|
||
c->single_char = (strlen (c->right) == 1);
|
||
}
|
||
c->keyword = syntax_malloc (MAX_WORDS_PER_CONTEXT * sizeof (struct key_word *));
|
||
#if 0
|
||
c->max_words = MAX_WORDS_PER_CONTEXT;
|
||
#endif
|
||
num_words = 1;
|
||
c->keyword[0] = syntax_malloc (sizeof (struct key_word));
|
||
fg = *a;
|
||
if (*a)
|
||
a++;
|
||
bg = *a;
|
||
if (*a)
|
||
a++;
|
||
strcpy (last_fg, fg ? fg : "");
|
||
strcpy (last_bg, bg ? bg : "");
|
||
#ifdef MIDNIGHT
|
||
c->keyword[0]->fg = this_try_alloc_color_pair (fg, bg);
|
||
#else
|
||
c->keyword[0]->fg = this_allocate_color (edit, fg);
|
||
c->keyword[0]->bg = this_allocate_color (edit, bg);
|
||
#endif
|
||
c->keyword[0]->keyword = (char *) strdup (" ");
|
||
check_not_a;
|
||
num_contexts++;
|
||
} else if (!strcmp (args[0], "spellcheck")) {
|
||
if (!c) {
|
||
result = line;
|
||
break;
|
||
}
|
||
c->spelling = 1;
|
||
} else if (!strcmp (args[0], "keyword")) {
|
||
struct key_word *k;
|
||
if (num_words == -1)
|
||
*a = 0;
|
||
check_a;
|
||
k = r[num_contexts - 1]->keyword[num_words] = syntax_malloc (sizeof (struct key_word));
|
||
if (!strcmp (*a, "whole")) {
|
||
a++;
|
||
k->whole_word_chars_left = (char *) strdup (whole_left);
|
||
k->whole_word_chars_right = (char *) strdup (whole_right);
|
||
} else if (!strcmp (*a, "wholeleft")) {
|
||
a++;
|
||
k->whole_word_chars_left = (char *) strdup (whole_left);
|
||
} else if (!strcmp (*a, "wholeright")) {
|
||
a++;
|
||
k->whole_word_chars_right = (char *) strdup (whole_right);
|
||
}
|
||
check_a;
|
||
if (!strcmp (*a, "linestart")) {
|
||
a++;
|
||
k->line_start = 1;
|
||
}
|
||
check_a;
|
||
if (!strcmp (*a, "whole")) {
|
||
*a = 0;
|
||
check_a;
|
||
}
|
||
k->keyword = (char *) strdup (*a++);
|
||
k->first = *k->keyword;
|
||
fg = *a;
|
||
if (*a)
|
||
a++;
|
||
bg = *a;
|
||
if (*a)
|
||
a++;
|
||
if (!fg)
|
||
fg = last_fg;
|
||
if (!bg)
|
||
bg = last_bg;
|
||
#ifdef MIDNIGHT
|
||
k->fg = this_try_alloc_color_pair (fg, bg);
|
||
#else
|
||
k->fg = this_allocate_color (edit, fg);
|
||
k->bg = this_allocate_color (edit, bg);
|
||
#endif
|
||
check_not_a;
|
||
num_words++;
|
||
} else if (!strncmp (args[0], "#", 1)) {
|
||
/* do nothing for comment */
|
||
} else if (!strcmp (args[0], "file")) {
|
||
break;
|
||
} else { /* anything else is an error */
|
||
*a = 0;
|
||
check_a;
|
||
}
|
||
free_args (args);
|
||
syntax_free (l);
|
||
}
|
||
free_args (args);
|
||
syntax_free (l);
|
||
|
||
if (!edit->rules[0])
|
||
syntax_free (edit->rules);
|
||
|
||
if (result)
|
||
return result;
|
||
|
||
if (num_contexts == -1) {
|
||
result = line;
|
||
return result;
|
||
}
|
||
|
||
{
|
||
char first_chars[MAX_WORDS_PER_CONTEXT + 2], *p;
|
||
for (i = 0; edit->rules[i]; i++) {
|
||
c = edit->rules[i];
|
||
p = first_chars;
|
||
*p++ = (char) 1;
|
||
for (j = 1; c->keyword[j]; j++)
|
||
*p++ = c->keyword[j]->first;
|
||
*p = '\0';
|
||
c->keyword_first_chars = syntax_malloc (strlen (first_chars) + 2);
|
||
strcpy (c->keyword_first_chars, first_chars);
|
||
}
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
#if !defined (GTK) && !defined (MIDNIGHT)
|
||
|
||
/* strdup and append c */
|
||
static char *strdupc (char *s, int c)
|
||
{
|
||
char *t;
|
||
int l;
|
||
strcpy (t = syntax_malloc ((l = strlen (s)) + 3), s);
|
||
t[l] = c;
|
||
t[l + 1] = '\0';
|
||
return t;
|
||
}
|
||
|
||
static void edit_syntax_clear_keyword (WEdit * edit, int context, int j)
|
||
{
|
||
struct context_rule *c;
|
||
struct _syntax_marker *s;
|
||
c = edit->rules[context];
|
||
/* first we clear any instances of this keyword in our cache chain (we used to just clear the cache chain, but this slows things down) */
|
||
for (s = edit->syntax_marker; s; s = s->next)
|
||
if (s->rule.keyword == j)
|
||
s->rule.keyword = 0;
|
||
else if (s->rule.keyword > j)
|
||
s->rule.keyword--;
|
||
syntax_free (c->keyword[j]->keyword);
|
||
syntax_free (c->keyword[j]->whole_word_chars_left);
|
||
syntax_free (c->keyword[j]->whole_word_chars_right);
|
||
syntax_free (c->keyword[j]);
|
||
memcpy (&c->keyword[j], &c->keyword[j + 1], (MAX_WORDS_PER_CONTEXT - j - 1) * sizeof (struct keyword *));
|
||
strcpy (&c->keyword_first_chars[j], &c->keyword_first_chars[j + 1]);
|
||
}
|
||
|
||
|
||
FILE *spelling_pipe_in = 0;
|
||
FILE *spelling_pipe_out = 0;
|
||
pid_t ispell_pid = 0;
|
||
|
||
|
||
/* adds a keyword for underlining into the keyword list for this context, returns 1 if too many words */
|
||
static int edit_syntax_add_keyword (WEdit * edit, char *keyword, int context, time_t t)
|
||
{
|
||
int j;
|
||
char *s;
|
||
struct context_rule *c;
|
||
c = edit->rules[context];
|
||
for (j = 1; c->keyword[j]; j++) {
|
||
/* if a keyword has been around for more than TRANSIENT_WORD_TIME_OUT
|
||
seconds, then remove it - we don't want to run out of space or makes syntax highlighting to slow */
|
||
if (c->keyword[j]->time) {
|
||
if (c->keyword[j]->time + TRANSIENT_WORD_TIME_OUT < t) {
|
||
edit->force |= REDRAW_PAGE;
|
||
edit_syntax_clear_keyword (edit, context, j);
|
||
j--;
|
||
}
|
||
}
|
||
}
|
||
/* are we out of space? */
|
||
if (j >= MAX_WORDS_PER_CONTEXT - 2)
|
||
return 1;
|
||
/* add the new keyword and date it */
|
||
c->keyword[j + 1] = 0;
|
||
c->keyword[j] = syntax_malloc (sizeof (struct key_word));
|
||
#ifdef MIDNIGHT
|
||
c->keyword[j]->fg = SPELLING_ERROR;
|
||
#else
|
||
c->keyword[j]->fg = c->keyword[0]->fg;
|
||
c->keyword[j]->bg = SPELLING_ERROR;
|
||
#endif
|
||
c->keyword[j]->keyword = (char *) strdup (keyword);
|
||
c->keyword[j]->first = *c->keyword[j]->keyword;
|
||
c->keyword[j]->whole_word_chars_left = (char *) strdup ("-'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ<59><5A><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
|
||
c->keyword[j]->whole_word_chars_right = (char *) strdup ("-'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ<59><5A><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
|
||
c->keyword[j]->time = t;
|
||
s = strdupc (c->keyword_first_chars, c->keyword[j]->first);
|
||
syntax_free (c->keyword_first_chars);
|
||
c->keyword_first_chars = s;
|
||
return 0;
|
||
}
|
||
|
||
/* checks spelling of the word at offset */
|
||
static int edit_check_spelling_at (WEdit * edit, long byte_index)
|
||
{
|
||
int context;
|
||
long p1, p2;
|
||
unsigned char *p, *q;
|
||
int r, c1, c2, j;
|
||
int ch;
|
||
time_t t;
|
||
struct context_rule *c;
|
||
/* sanity check */
|
||
if (!edit->rules || byte_index > edit->last_byte)
|
||
return 0;
|
||
/* in what context are we */
|
||
context = edit_get_rule (edit, byte_index).context;
|
||
c = edit->rules[context];
|
||
/* does this context have `spellcheck' */
|
||
if (!edit->rules[context]->spelling)
|
||
return 0;
|
||
/* find word start */
|
||
for (p1 = byte_index - 1;; p1--) {
|
||
ch = edit_get_byte (edit, p1);
|
||
if (isalpha (ch) || ch == '-' || ch == '\'')
|
||
continue;
|
||
break;
|
||
}
|
||
p1++;
|
||
/* find word end */
|
||
for (p2 = byte_index;; p2++) {
|
||
ch = edit_get_byte (edit, p2);
|
||
if (isalpha (ch) || ch == '-' || ch == '\'')
|
||
continue;
|
||
break;
|
||
}
|
||
if (p2 <= p1)
|
||
return 0;
|
||
/* create string */
|
||
q = p = syntax_malloc (p2 - p1 + 2);
|
||
for (; p1 < p2; p1++)
|
||
*p++ = edit_get_byte (edit, p1);
|
||
*p = '\0';
|
||
if (q[0] == '-' || strlen ((char *) q) > 40) { /* if you are using words over 40 characters, you are on your own */
|
||
syntax_free (q);
|
||
return 0;
|
||
}
|
||
time (&t);
|
||
for (j = 1; c->keyword[j]; j++) {
|
||
/* if the keyword is present, then update its time only. if it is a fixed keyword from the rules file, then just return */
|
||
if (!strcmp (c->keyword[j]->keyword, (char *) q)) {
|
||
if (c->keyword[j]->time)
|
||
c->keyword[j]->time = t;
|
||
syntax_free (q);
|
||
return 0;
|
||
}
|
||
}
|
||
/* feed it to ispell */
|
||
fprintf (spelling_pipe_out, "%s\n", (char *) q);
|
||
fflush (spelling_pipe_out);
|
||
/* what does ispell say? */
|
||
do {
|
||
r = fgetc (spelling_pipe_in);
|
||
} while (r == -1 && errno == EINTR);
|
||
if (r == -1) {
|
||
syntax_free (q);
|
||
return 1;
|
||
}
|
||
if (r == '\n') { /* ispell sometimes returns just blank line if it is given bad characters */
|
||
syntax_free (q);
|
||
return 0;
|
||
}
|
||
/* now read ispell output untill we get two blanks lines - we are not intersted in this part */
|
||
do {
|
||
c1 = fgetc (spelling_pipe_in);
|
||
} while (c1 == -1 && errno == EINTR);
|
||
for (;;) {
|
||
if (c1 == -1) {
|
||
syntax_free (q);
|
||
return 1;
|
||
}
|
||
do {
|
||
c2 = fgetc (spelling_pipe_in);
|
||
} while (c2 == -1 && errno == EINTR);
|
||
if (c1 == '\n' && c2 == '\n')
|
||
break;
|
||
c1 = c2;
|
||
}
|
||
/* spelled ok */
|
||
if (r == '*' || r == '+' || r == '-') {
|
||
syntax_free (q);
|
||
return 0;
|
||
}
|
||
/* not spelled ok - so add a syntax keyword for this word */
|
||
edit_syntax_add_keyword (edit, (char *) q, context, t);
|
||
syntax_free (q);
|
||
return 0;
|
||
}
|
||
|
||
char *option_alternate_dictionary = "";
|
||
|
||
int edit_check_spelling (WEdit * edit)
|
||
{
|
||
if (!option_auto_spellcheck)
|
||
return 0;
|
||
/* magic arg to close up shop */
|
||
if (!edit) {
|
||
option_auto_spellcheck = 0;
|
||
goto close_spelling;
|
||
}
|
||
/* do we at least have a syntax rule struct to put new wrongly spelled keyword in for highlighting? */
|
||
if (!edit->rules && !edit->explicit_syntax)
|
||
edit_load_syntax (edit, 0, UNKNOWN_FORMAT);
|
||
if (!edit->rules) {
|
||
option_auto_spellcheck = 0;
|
||
return 0;
|
||
}
|
||
/* is ispell running? */
|
||
if (!spelling_pipe_in) {
|
||
int in, out, a = 0;
|
||
char *arg[10];
|
||
arg[a++] = "ispell";
|
||
arg[a++] = "-a";
|
||
if (option_alternate_dictionary)
|
||
if (*option_alternate_dictionary) {
|
||
arg[a++] = "-d";
|
||
arg[a++] = option_alternate_dictionary;
|
||
}
|
||
arg[a++] = "-a";
|
||
arg[a++] = 0;
|
||
/* start ispell process */
|
||
ispell_pid = triple_pipe_open (&in, &out, 0, 1, arg[0], arg);
|
||
if (ispell_pid < 1) {
|
||
option_auto_spellcheck = 0;
|
||
#if 0
|
||
CErrorDialog (0, 0, 0, _ (" Spelling Message "), "%s", _ (" Fail trying to open ispell program. \n Check that it is in your path and works with the -a option. \n Alternatively, disable spell checking from the Options menu. "));
|
||
#endif
|
||
return 1;
|
||
}
|
||
/* prepare pipes */
|
||
spelling_pipe_in = (FILE *) fdopen (out, "r");
|
||
spelling_pipe_out = (FILE *) fdopen (in, "w");
|
||
if (!spelling_pipe_in || !spelling_pipe_out) {
|
||
option_auto_spellcheck = 0;
|
||
CErrorDialog (0, 0, 0, _ (" Spelling Message "), "%s", _ (" Fail trying to open ispell pipes. \n Check that it is in your path and works with the -a option. \n Alternatively, disable spell checking from the Options menu. "));
|
||
return 1;
|
||
}
|
||
/* read the banner message */
|
||
for (;;) {
|
||
int c1;
|
||
c1 = fgetc (spelling_pipe_in);
|
||
if (c1 == -1 && errno != EINTR) {
|
||
option_auto_spellcheck = 0;
|
||
CErrorDialog (0, 0, 0, _ (" Spelling Message "), "%s", _ (" Fail trying to read ispell pipes. \n Check that it is in your path and works with the -a option. \n Alternatively, disable spell checking from the Options menu. "));
|
||
return 1;
|
||
}
|
||
if (c1 == '\n')
|
||
break;
|
||
}
|
||
}
|
||
/* spellcheck the word under the cursor */
|
||
if (edit_check_spelling_at (edit, edit->curs1)) {
|
||
CMessageDialog (0, 0, 0, 0, _ (" Spelling Message "), "%s", _ (" Error reading from ispell. \n Ispell is being restarted. "));
|
||
close_spelling:
|
||
fclose (spelling_pipe_in);
|
||
spelling_pipe_in = 0;
|
||
fclose (spelling_pipe_out);
|
||
spelling_pipe_out = 0;
|
||
kill (ispell_pid, SIGKILL);
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
#else /* ! GTK && ! MIDNIGHT*/
|
||
|
||
int edit_check_spelling (WEdit * edit)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
#endif
|
||
|
||
void (*syntax_change_callback) (CWidget *) = 0;
|
||
|
||
void edit_set_syntax_change_callback (void (*callback) (CWidget *))
|
||
{
|
||
syntax_change_callback = callback;
|
||
}
|
||
|
||
void edit_free_syntax_rules (WEdit * edit)
|
||
{
|
||
int i, j;
|
||
if (!edit)
|
||
return;
|
||
if (!edit->rules)
|
||
return;
|
||
edit_get_rule (edit, -1);
|
||
syntax_free (edit->syntax_type);
|
||
edit->syntax_type = 0;
|
||
if (syntax_change_callback)
|
||
#ifdef MIDNIGHT
|
||
(*syntax_change_callback) (&edit->widget);
|
||
#else
|
||
(*syntax_change_callback) (edit->widget);
|
||
#endif
|
||
for (i = 0; edit->rules[i]; i++) {
|
||
if (edit->rules[i]->keyword) {
|
||
for (j = 0; edit->rules[i]->keyword[j]; j++) {
|
||
syntax_free (edit->rules[i]->keyword[j]->keyword);
|
||
syntax_free (edit->rules[i]->keyword[j]->whole_word_chars_left);
|
||
syntax_free (edit->rules[i]->keyword[j]->whole_word_chars_right);
|
||
syntax_free (edit->rules[i]->keyword[j]);
|
||
}
|
||
}
|
||
syntax_free (edit->rules[i]->left);
|
||
syntax_free (edit->rules[i]->right);
|
||
syntax_free (edit->rules[i]->whole_word_chars_left);
|
||
syntax_free (edit->rules[i]->whole_word_chars_right);
|
||
syntax_free (edit->rules[i]->keyword);
|
||
syntax_free (edit->rules[i]->keyword_first_chars);
|
||
syntax_free (edit->rules[i]);
|
||
}
|
||
while (edit->syntax_marker) {
|
||
struct _syntax_marker *s = edit->syntax_marker->next;
|
||
syntax_free (edit->syntax_marker);
|
||
edit->syntax_marker = s;
|
||
}
|
||
syntax_free (edit->rules);
|
||
}
|
||
|
||
#define CURRENT_SYNTAX_RULES_VERSION "62"
|
||
|
||
static const char * const syntax_text[] = {
|
||
"# syntax rules version " CURRENT_SYNTAX_RULES_VERSION,
|
||
"# (after the slash is a Cooledit color, 0-26 or any of the X colors in rgb.txt)",
|
||
"# black",
|
||
"# red",
|
||
"# green",
|
||
"# brown",
|
||
"# blue",
|
||
"# magenta",
|
||
"# cyan",
|
||
"# lightgray",
|
||
"# gray",
|
||
"# brightred",
|
||
"# brightgreen",
|
||
"# yellow",
|
||
"# brightblue",
|
||
"# brightmagenta",
|
||
"# brightcyan",
|
||
"# white",
|
||
"",
|
||
"file gobledy_gook #\\sHelp\\ssupport\\sother\\sfile\\stypes",
|
||
"context default",
|
||
"file gobledy_gook #\\sby\\scoding\\srules\\sin\\s~/.cedit/syntax.",
|
||
"context default",
|
||
"file gobledy_gook #\\sSee\\sman/syntax\\sin\\sthe\\ssource\\sdistribution",
|
||
"context default",
|
||
"file gobledy_gook #\\sand\\sconsult\\sthe\\sman\\spage.",
|
||
"context default",
|
||
"",
|
||
"",
|
||
"file ..\\*\\\\.(diff|rej|patch)$ Diff\\sOutput ^diff",
|
||
"include diff.syntax",
|
||
"",
|
||
"file ..\\*\\\\.lsm$ LSM\\sFile",
|
||
"include lsm.syntax",
|
||
"",
|
||
"file ..\\*\\\\.sh$ Shell\\sScript ^#!\\s\\*/.\\*/(ksh|bash|sh|pdkzsh)",
|
||
"include sh.syntax",
|
||
"",
|
||
"file ..\\*\\\\.(pl|PL|pm|PM])$ Perl\\sProgram ^#!\\s\\*/.\\*/perl",
|
||
"include perl.syntax",
|
||
"",
|
||
"file ..\\*\\\\.(py|PY])$ Python\\sProgram ^#!\\s\\*/.\\*/python",
|
||
"include python.syntax",
|
||
"",
|
||
"file ..\\*\\\\.(man|[0-9n]|[0-9]x)$ NROFF\\sSource",
|
||
"include nroff.syntax",
|
||
"",
|
||
"file ..\\*\\\\.(htm|html|HTM|HTML)$ HTML\\sFile",
|
||
"include html.syntax",
|
||
"",
|
||
"file ..\\*\\\\.(pp|PP|pas|PAS)$ Pascal\\sProgram",
|
||
"include pascal.syntax",
|
||
"",
|
||
"file ..\\*\\\\.(ada|adb|ads|ADA|ADB|ADS)$ Ada\\sProgram",
|
||
"include ada95.syntax",
|
||
"",
|
||
"file ..\\*\\\\.(sl|SL)$ S-Lang\\sProgram",
|
||
"include slang.syntax",
|
||
"",
|
||
"file ..\\*\\\\.tex$ LaTeX\\s2.09\\sDocument",
|
||
"include latex.syntax",
|
||
"",
|
||
"file ..\\*\\.(texi|texinfo|TEXI|TEXINFO)$ Texinfo\\sDocument",
|
||
"include texinfo.syntax",
|
||
"",
|
||
"file ..\\*\\\\.([chC]|CC|cxx|cc|cpp|CPP|CXX)$ C/C\\+\\+\\sProgram",
|
||
"include c.syntax",
|
||
"",
|
||
"file ..\\*\\\\.[fF]$ Fortran\\sProgram",
|
||
"include fortran.syntax",
|
||
"",
|
||
"file ..\\*\\\\.i$ SWIG\\sSource",
|
||
"include swig.syntax",
|
||
"",
|
||
"file ..\\*\\\\.(java|JAVA|Java|jav)$ Java\\sProgram",
|
||
"include java.syntax",
|
||
"",
|
||
"file ..\\*\\\\.(st)$ SmallTalk\\sProgram",
|
||
"include smalltalk.syntax",
|
||
"",
|
||
"file ..\\*\\\\.(ml|mli|mly|mll|mlp)$ ML\\sProgram",
|
||
"include ml.syntax",
|
||
"",
|
||
"file ..\\*\\\\.m$ Matlab\\sor\\sOctave\\sFile",
|
||
"include octave.syntax",
|
||
"",
|
||
"file .\\*ChangeLog$ GNU\\sDistribution\\sChangeLog\\sFile",
|
||
"include changelog.syntax",
|
||
"",
|
||
"file .\\*[Mm]akefile[\\\\\\.a-z]\\*$ Makefile",
|
||
"include makefile.syntax",
|
||
"",
|
||
"file Don_t_match_me Mail\\sfolder ^From\\s",
|
||
"include mail.syntax",
|
||
"",
|
||
"file .\\*syntax$ Syntax\\sHighlighting\\sdefinitions",
|
||
"",
|
||
"context default",
|
||
" keyword whole spellch\\eck yellow/24",
|
||
" keyword whole keyw\\ord yellow/24",
|
||
" keyword whole whole\\[\\t\\s\\]l\\inestart brightcyan/17",
|
||
" keyword whole whole\\[\\t\\s\\]l\\inestart brightcyan/17",
|
||
" keyword whole wh\\oleleft\\[\\t\\s\\]l\\inestart brightcyan/17",
|
||
" keyword whole wh\\oleright\\[\\t\\s\\]l\\inestart brightcyan/17",
|
||
" keyword whole l\\inestart\\[\\t\\s\\]wh\\ole",
|
||
" keyword whole l\\inestart\\[\\t\\s\\]wh\\ole",
|
||
" keyword whole l\\inestart\\[\\t\\s\\]wh\\oleleft",
|
||
" keyword whole l\\inestart\\[\\t\\s\\]wh\\oleright",
|
||
" keyword wholeleft whole\\s brightcyan/17",
|
||
" keyword wholeleft whole\\t brightcyan/17",
|
||
" keyword whole wh\\oleleft brightcyan/17",
|
||
" keyword whole wh\\oleright brightcyan/17",
|
||
" keyword whole lin\\[e\\]start brightcyan/17",
|
||
" keyword whole c\\ontext\\[\\t\\s\\]exclusive brightred/18",
|
||
" keyword whole c\\ontext\\[\\t\\s\\]default brightred/18",
|
||
" keyword whole c\\ontext brightred/18",
|
||
" keyword whole wh\\olechars\\[\\t\\s\\]left brightcyan/17",
|
||
" keyword whole wh\\olechars\\[\\t\\s\\]right brightcyan/17",
|
||
" keyword whole wh\\olechars brightcyan/17",
|
||
" keyword whole f\\ile brightgreen/6",
|
||
" keyword whole in\\clude brightred/18",
|
||
"",
|
||
" keyword whole 0 lightgray/0 blue/26",
|
||
" keyword whole 1 lightgray/1 blue/26",
|
||
" keyword whole 2 lightgray/2 blue/26",
|
||
" keyword whole 3 lightgray/3 blue/26",
|
||
" keyword whole 4 lightgray/4 blue/26",
|
||
" keyword whole 5 lightgray/5 blue/26",
|
||
" keyword whole 6 lightgray/6",
|
||
" keyword whole 7 lightgray/7",
|
||
" keyword whole 8 lightgray/8",
|
||
" keyword whole 9 lightgray/9",
|
||
" keyword whole 10 lightgray/10",
|
||
" keyword whole 11 lightgray/11",
|
||
" keyword whole 12 lightgray/12",
|
||
" keyword whole 13 lightgray/13",
|
||
" keyword whole 14 lightgray/14",
|
||
" keyword whole 15 lightgray/15",
|
||
" keyword whole 16 lightgray/16",
|
||
" keyword whole 17 lightgray/17",
|
||
" keyword whole 18 lightgray/18",
|
||
" keyword whole 19 lightgray/19",
|
||
" keyword whole 20 lightgray/20",
|
||
" keyword whole 21 lightgray/21",
|
||
" keyword whole 22 lightgray/22",
|
||
" keyword whole 23 lightgray/23",
|
||
" keyword whole 24 lightgray/24",
|
||
" keyword whole 25 lightgray/25",
|
||
" keyword whole 26 lightgray/26",
|
||
"",
|
||
" keyword wholeleft black\\/ black/0",
|
||
" keyword wholeleft red\\/ red/DarkRed",
|
||
" keyword wholeleft green\\/ green/green3",
|
||
" keyword wholeleft brown\\/ brown/saddlebrown",
|
||
" keyword wholeleft blue\\/ blue/blue3",
|
||
" keyword wholeleft magenta\\/ magenta/magenta3",
|
||
" keyword wholeleft cyan\\/ cyan/cyan3",
|
||
" keyword wholeleft lightgray\\/ lightgray/lightgray",
|
||
" keyword wholeleft gray\\/ gray/gray",
|
||
" keyword wholeleft brightred\\/ brightred/red",
|
||
" keyword wholeleft brightgreen\\/ brightgreen/green1",
|
||
" keyword wholeleft yellow\\/ yellow/yellow",
|
||
" keyword wholeleft brightblue\\/ brightblue/blue1",
|
||
" keyword wholeleft brightmagenta\\/ brightmagenta/magenta",
|
||
" keyword wholeleft brightcyan\\/ brightcyan/cyan1",
|
||
" keyword wholeleft white\\/ white/26",
|
||
"",
|
||
"context linestart # \\n brown/22",
|
||
"",
|
||
"file .\\* " UNKNOWN_FORMAT,
|
||
"include unknown.syntax",
|
||
"",
|
||
0};
|
||
|
||
|
||
FILE *upgrade_syntax_file (char *syntax_file)
|
||
{
|
||
FILE *f;
|
||
char *p;
|
||
char line[80];
|
||
f = fopen (syntax_file, "r");
|
||
if (!f) {
|
||
const char * const *syntax_line;
|
||
rewrite_rule_file:
|
||
f = fopen (syntax_file, "w");
|
||
if (!f)
|
||
return 0;
|
||
for (syntax_line = syntax_text; *syntax_line; syntax_line++)
|
||
fprintf (f, "%s\n", *syntax_line);
|
||
fclose (f);
|
||
return fopen (syntax_file, "r");
|
||
}
|
||
memset (line, 0, sizeof (line));
|
||
fread (line, sizeof (line) - 1, 1, f);
|
||
if (!strstr (line, "syntax rules version"))
|
||
goto rename_rule_file;
|
||
p = strstr (line, "version") + strlen ("version") + 1;
|
||
if (atoi (p) < atoi (CURRENT_SYNTAX_RULES_VERSION)) {
|
||
char s[1024];
|
||
rename_rule_file:
|
||
fclose (f);
|
||
strcpy (s, syntax_file);
|
||
strcat (s, ".OLD");
|
||
unlink (s);
|
||
rename (syntax_file, s);
|
||
unlink (syntax_file); /* might rename() fail ? */
|
||
#if defined(MIDNIGHT) || defined(GTK)
|
||
edit_message_dialog (_(" Load Syntax Rules "), _(" Your syntax rule file is outdated \n A new rule file is being installed. \n Your old rule file has been saved with a .OLD extension. "));
|
||
#else
|
||
CMessageDialog (0, 20, 20, 0,_(" Load Syntax Rules "), _(" Your syntax rule file is outdated \n A new rule file is being installed. \n Your old rule file has been saved with a .OLD extension. "));
|
||
#endif
|
||
goto rewrite_rule_file;
|
||
}
|
||
rewind (f);
|
||
return f;
|
||
}
|
||
|
||
/* returns -1 on file error, line number on error in file syntax */
|
||
static int edit_read_syntax_file (WEdit * edit, char **names, char *syntax_file, char *editor_file, char *first_line, char *type)
|
||
{
|
||
FILE *f;
|
||
regex_t r;
|
||
regmatch_t pmatch[1];
|
||
char *args[1024], *l = 0;
|
||
int line = 0;
|
||
int argc;
|
||
int result = 0;
|
||
int count = 0;
|
||
f = upgrade_syntax_file (syntax_file);
|
||
if (!f)
|
||
return -1;
|
||
args[0] = 0;
|
||
for (;;) {
|
||
line++;
|
||
syntax_free (l);
|
||
if (!read_one_line (&l, f))
|
||
break;
|
||
get_args (l, args, &argc);
|
||
if (!args[0])
|
||
continue;
|
||
/* looking for `file ...' lines only */
|
||
if (strcmp (args[0], "file")) {
|
||
free_args (args);
|
||
continue;
|
||
}
|
||
/* must have two args or report error */
|
||
if (!args[1] || !args[2]) {
|
||
result = line;
|
||
break;
|
||
}
|
||
if (names) {
|
||
/* 1: just collecting a list of names of rule sets */
|
||
names[count++] = (char *) strdup (args[2]);
|
||
names[count] = 0;
|
||
} else if (type) {
|
||
/* 2: rule set was explicitly specified by the caller */
|
||
if (!strcmp (type, args[2]))
|
||
goto found_type;
|
||
} else if (editor_file && edit) {
|
||
/* 3: auto-detect rule set from regular expressions */
|
||
int q;
|
||
if (regcomp (&r, args[1], REG_EXTENDED)) {
|
||
result = line;
|
||
break;
|
||
}
|
||
/* does filename match arg 1 ? */
|
||
q = !regexec (&r, editor_file, 1, pmatch, 0);
|
||
regfree (&r);
|
||
if (!q && args[3]) {
|
||
if (regcomp (&r, args[3], REG_EXTENDED)) {
|
||
result = line;
|
||
break;
|
||
}
|
||
/* does first line match arg 3 ? */
|
||
q = !regexec (&r, first_line, 1, pmatch, 0);
|
||
regfree (&r);
|
||
}
|
||
if (q) {
|
||
int line_error;
|
||
found_type:
|
||
line_error = edit_read_syntax_rules (edit, f);
|
||
if (line_error) {
|
||
if (!error_file_name) /* an included file */
|
||
result = line + line_error;
|
||
else
|
||
result = line_error;
|
||
} else {
|
||
syntax_free (edit->syntax_type);
|
||
edit->syntax_type = (char *) strdup (args[2]);
|
||
/* if there are no rules then turn off syntax highlighting for speed */
|
||
if (!edit->rules[1])
|
||
if (!edit->rules[0]->keyword[1] && !edit->rules[0]->spelling) {
|
||
edit_free_syntax_rules (edit);
|
||
break;
|
||
}
|
||
/* notify the callback of a change in rule set */
|
||
if (syntax_change_callback)
|
||
#ifdef MIDNIGHT
|
||
(*syntax_change_callback) (&edit->widget);
|
||
#else
|
||
(*syntax_change_callback) (edit->widget);
|
||
#endif
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
free_args (args);
|
||
}
|
||
free_args (args);
|
||
syntax_free (l);
|
||
fclose (f);
|
||
return result;
|
||
}
|
||
|
||
static char *get_first_editor_line (WEdit * edit)
|
||
{
|
||
int i;
|
||
static char s[256];
|
||
s[0] = '\0';
|
||
if (!edit)
|
||
return s;
|
||
for (i = 0; i < 255; i++) {
|
||
s[i] = edit_get_byte (edit, i);
|
||
if (s[i] == '\n') {
|
||
s[i] = '\0';
|
||
break;
|
||
}
|
||
}
|
||
s[255] = '\0';
|
||
return s;
|
||
}
|
||
|
||
/* loads rules into edit struct. one of edit or names must be zero. if
|
||
edit is zero, a list of types will be stored into name. type may be zero
|
||
in which case the type will be selected according to the filename. */
|
||
void edit_load_syntax (WEdit * edit, char **names, char *type)
|
||
{
|
||
int r;
|
||
char *f;
|
||
|
||
edit_free_syntax_rules (edit);
|
||
|
||
if (!option_syntax_highlighting)
|
||
return;
|
||
|
||
if (edit) {
|
||
if (!edit->filename)
|
||
return;
|
||
if (!*edit->filename && !type)
|
||
return;
|
||
}
|
||
f = catstrs (home_dir, SYNTAX_FILE, 0);
|
||
r = edit_read_syntax_file (edit, names, f, edit ? edit->filename : 0, get_first_editor_line (edit), type);
|
||
if (r == -1) {
|
||
edit_free_syntax_rules (edit);
|
||
edit_error_dialog (_ (" Load syntax file "), _ (" File access error "));
|
||
return;
|
||
}
|
||
if (r) {
|
||
char s[80];
|
||
edit_free_syntax_rules (edit);
|
||
sprintf (s, _ (" Error in file %s on line %d "), error_file_name ? error_file_name : f, r);
|
||
edit_error_dialog (_ (" Load syntax file "), s);
|
||
syntax_free (error_file_name);
|
||
return;
|
||
}
|
||
}
|
||
|
||
#else
|
||
|
||
int option_syntax_highlighting = 0;
|
||
|
||
void edit_load_syntax (WEdit * edit, char **names, char *type)
|
||
{
|
||
return;
|
||
}
|
||
|
||
void edit_free_syntax_rules (WEdit * edit)
|
||
{
|
||
return;
|
||
}
|
||
|
||
void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg)
|
||
{
|
||
*fg = NORMAL_COLOR;
|
||
}
|
||
|
||
int edit_check_spelling (WEdit * edit)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
#endif /* !defined(MIDNIGHT) || defined(HAVE_SYNTAXH) */
|
||
|