1998-09-15 00:18:54 +04:00
/* editor syntax highlighting.
Copyright ( C ) 1996 , 1997 , 1998 the Free Software Foundation
Authors : 1998 Paul Sheer
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
1999-03-21 04:56:20 +03:00
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA
02111 - 1307 , USA .
*/
1998-09-15 00:18:54 +04:00
# include <config.h>
# if defined(MIDNIGHT) || defined(GTK)
# include "edit.h"
# else
# include "coolwidget.h"
# endif
1999-07-22 00:03:23 +04:00
# if defined (HAVE_MAD) && ! defined (MIDNIGHT) && ! defined (GTK)
# include "mad.h"
# endif
1998-09-15 00:18:54 +04:00
1998-12-10 18:43:32 +03:00
/* bytes */
# define SYNTAX_MARKER_DENSITY 512
1999-07-22 00:03:23 +04:00
/*
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"
1998-09-15 00:18:54 +04:00
# if !defined(MIDNIGHT) || defined(HAVE_SYNTAXH)
int option_syntax_highlighting = 1 ;
1999-07-22 00:03:23 +04:00
int option_auto_spellcheck = 1 ;
1998-09-15 00:18:54 +04:00
/* 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 ) ;
static void * syntax_malloc ( size_t x )
{
void * p ;
p = malloc ( x ) ;
memset ( p , 0 , x ) ;
return p ;
}
# define syntax_free(x) {if(x){free(x);(x)=0;}}
1999-07-22 00:03:23 +04:00
static long compare_word_to_right ( WEdit * edit , long i , char * text , char * whole_left , char * whole_right , int line_start )
1998-09-15 00:18:54 +04:00
{
1999-07-22 00:03:23 +04:00
unsigned char * p , * q ;
1998-09-15 00:18:54 +04:00
int c , d , j ;
if ( ! * text )
1999-07-22 00:03:23 +04:00
return - 1 ;
1998-09-15 00:18:54 +04:00
c = edit_get_byte ( edit , i - 1 ) ;
if ( line_start )
if ( c ! = ' \n ' )
1999-07-22 00:03:23 +04:00
return - 1 ;
1998-09-15 00:18:54 +04:00
if ( whole_left )
if ( strchr ( whole_left , c ) )
1999-07-22 00:03:23 +04:00
return - 1 ;
for ( p = ( unsigned char * ) text , q = p + strlen ( ( char * ) p ) ; ( unsigned long ) p < ( unsigned long ) q ; p + + , i + + ) {
1998-09-15 00:18:54 +04:00
switch ( * p ) {
case ' \001 ' :
p + + ;
for ( ; ; ) {
c = edit_get_byte ( edit , i ) ;
1999-07-22 00:03:23 +04:00
if ( ! * p )
if ( whole_right )
if ( ! strchr ( whole_right , c ) )
break ;
1998-09-15 00:18:54 +04:00
if ( c = = * p )
break ;
if ( c = = ' \n ' )
1999-07-22 00:03:23 +04:00
return - 1 ;
1998-09-15 00:18:54 +04:00
i + + ;
}
break ;
case ' \002 ' :
p + + ;
j = 0 ;
for ( ; ; ) {
c = edit_get_byte ( edit , i ) ;
1999-07-22 00:03:23 +04:00
if ( c = = * p ) {
1998-09-15 00:18:54 +04:00
j = i ;
1999-07-22 00:03:23 +04:00
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 */
1998-09-15 00:18:54 +04:00
break ;
if ( c = = ' \n ' | | c = = ' \t ' | | c = = ' ' ) {
1999-07-22 00:03:23 +04:00
if ( ! * p ) {
i - - ;
break ;
}
1998-09-15 00:18:54 +04:00
if ( ! j )
1999-07-22 00:03:23 +04:00
return - 1 ;
1998-09-15 00:18:54 +04:00
i = j ;
break ;
}
if ( whole_right )
if ( ! strchr ( whole_right , c ) ) {
1999-07-22 00:03:23 +04:00
if ( ! * p ) {
i - - ;
break ;
}
1998-09-15 00:18:54 +04:00
if ( ! j )
1999-07-22 00:03:23 +04:00
return - 1 ;
1998-09-15 00:18:54 +04:00
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 + + ;
1999-07-22 00:03:23 +04:00
c = edit_get_byte ( edit , i ) ;
for ( ; * p ! = ' \004 ' ; p + + )
if ( c = = * p )
goto found_char3 ;
return - 1 ;
found_char3 :
for ( ; * p ! = ' \004 ' ; p + + ) ;
1998-09-15 00:18:54 +04:00
break ;
default :
if ( * p ! = edit_get_byte ( edit , i ) )
1999-07-22 00:03:23 +04:00
return - 1 ;
1998-09-15 00:18:54 +04:00
}
}
if ( whole_right )
if ( strchr ( whole_right , edit_get_byte ( edit , i ) ) )
1999-07-22 00:03:23 +04:00
return - 1 ;
return i ;
1998-09-15 00:18:54 +04:00
}
1999-07-22 00:03:23 +04:00
# define XXX \
if ( * s < ' \005 ' | | * s = = ( unsigned char ) c ) \
goto done ; \
s + + ;
static inline char * xx_strchr ( const unsigned char * s , int c )
1998-09-15 00:18:54 +04:00
{
1999-07-22 00:03:23 +04:00
repeat :
XXX XXX XXX XXX XXX XXX XXX XXX ;
XXX XXX XXX XXX XXX XXX XXX XXX ;
goto repeat ;
done :
return ( char * ) s ;
1998-09-15 00:18:54 +04:00
}
1999-07-22 00:03:23 +04:00
static inline struct syntax_rule apply_rules_going_right ( WEdit * edit , long i , struct syntax_rule rule )
1998-09-15 00:18:54 +04:00
{
struct context_rule * r ;
1999-07-22 00:03:23 +04:00
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 ) ) )
1998-09-15 00:18:54 +04:00
return rule ;
1999-07-22 00:03:23 +04:00
is_end = ( rule . end = = ( unsigned char ) i ) ;
1998-09-15 00:18:54 +04:00
/* check to turn off a keyword */
1999-07-22 00:03:23 +04:00
if ( _rule . keyword ) {
1998-09-15 00:18:54 +04:00
struct key_word * k ;
1999-07-22 00:03:23 +04:00
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 ;
1998-09-15 00:18:54 +04:00
keyword_foundleft = 1 ;
}
}
/* check to turn off a context */
1999-07-22 00:03:23 +04:00
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 ;
1998-09-15 00:18:54 +04:00
found_right = 1 ;
1999-07-22 00:03:23 +04:00
_rule . border = RULE_ON_RIGHT_BORDER ;
1998-09-15 00:18:54 +04:00
if ( r - > between_delimiters )
1999-07-22 00:03:23 +04:00
_rule . context = 0 ;
} else if ( is_end & & rule . border & RULE_ON_RIGHT_BORDER ) {
1998-09-15 00:18:54 +04:00
/* always turn off a context at 4 */
1999-07-22 00:03:23 +04:00
found_left = 1 ;
_rule . border = 0 ;
if ( ! keyword_foundleft )
_rule . context = 0 ;
} else if ( is_end & & rule . border & RULE_ON_LEFT_BORDER ) {
1998-09-15 00:18:54 +04:00
/* never turn off a context at 2 */
1999-07-22 00:03:23 +04:00
found_left = 1 ;
_rule . border = 0 ;
1998-09-15 00:18:54 +04:00
}
}
/* check to turn on a keyword */
1999-07-22 00:03:23 +04:00
if ( ! _rule . keyword ) {
1998-09-15 00:18:54 +04:00
char * p ;
1999-07-22 00:03:23 +04:00
p = ( r = edit - > rules [ _rule . context ] ) - > keyword_first_chars ;
while ( * ( p = xx_strchr ( ( unsigned char * ) p + 1 , c ) ) ) {
1998-09-15 00:18:54 +04:00
struct key_word * k ;
int count ;
1999-07-22 00:03:23 +04:00
long e ;
1998-09-15 00:18:54 +04:00
count = ( unsigned long ) p - ( unsigned long ) r - > keyword_first_chars ;
k = r - > keyword [ count ] ;
1999-07-22 00:03:23 +04:00
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 ;
1998-09-15 00:18:54 +04:00
break ;
}
}
}
/* check to turn on a context */
1999-07-22 00:03:23 +04:00
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 ;
1998-09-15 00:18:54 +04:00
contextchanged = 1 ;
1999-07-22 00:03:23 +04:00
_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 ;
1998-09-15 00:18:54 +04:00
}
}
}
1999-07-22 00:03:23 +04:00
}
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 ;
1998-09-15 00:18:54 +04:00
}
}
}
}
}
1999-07-22 00:03:23 +04:00
/* check again to turn on a keyword if the context switched */
if ( contextchanged & & ! _rule . keyword ) {
1998-09-15 00:18:54 +04:00
char * p ;
1999-07-22 00:03:23 +04:00
p = ( r = edit - > rules [ _rule . context ] ) - > keyword_first_chars ;
while ( * ( p = xx_strchr ( ( unsigned char * ) p + 1 , c ) ) ) {
1998-09-15 00:18:54 +04:00
struct key_word * k ;
1999-07-22 00:03:23 +04:00
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 ;
1998-09-15 00:18:54 +04:00
break ;
}
}
}
1999-07-22 00:03:23 +04:00
return _rule ;
1998-09-15 00:18:54 +04:00
}
1999-07-22 00:03:23 +04:00
static struct syntax_rule edit_get_rule ( WEdit * edit , long byte_index )
1998-09-15 00:18:54 +04:00
{
long i ;
if ( byte_index > edit - > last_get_rule ) {
1998-12-10 18:43:32 +03:00
for ( i = edit - > last_get_rule + 1 ; i < = byte_index ; i + + ) {
1998-09-15 00:18:54 +04:00
edit - > rule = apply_rules_going_right ( edit , i , edit - > rule ) ;
1998-12-10 18:43:32 +03:00
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 = malloc ( sizeof ( struct _syntax_marker ) ) ;
edit - > syntax_marker - > next = s ;
edit - > syntax_marker - > offset = i ;
edit - > syntax_marker - > rule = edit - > rule ;
}
}
1998-09-15 00:18:54 +04:00
} else if ( byte_index < edit - > last_get_rule ) {
1998-12-10 18:43:32 +03:00
struct _syntax_marker * s ;
for ( ; ; ) {
if ( ! edit - > syntax_marker ) {
1999-07-22 00:03:23 +04:00
memset ( & edit - > rule , 0 , sizeof ( edit - > rule ) ) ;
1998-12-10 18:43:32 +03:00
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 ;
}
1998-09-15 00:18:54 +04:00
}
edit - > last_get_rule = byte_index ;
return edit - > rule ;
}
1999-07-22 00:03:23 +04:00
static void translate_rule_to_color ( WEdit * edit , struct syntax_rule rule , int * fg , int * bg )
1998-09-15 00:18:54 +04:00
{
struct key_word * k ;
1999-07-22 00:03:23 +04:00
k = edit - > rules [ rule . context ] - > keyword [ rule . keyword ] ;
1998-09-15 00:18:54 +04:00
* bg = k - > bg ;
* fg = k - > fg ;
}
void edit_get_syntax_color ( WEdit * edit , long byte_index , int * fg , int * bg )
{
1999-07-22 00:03:23 +04:00
if ( edit - > rules & & byte_index < edit - > last_byte & & option_syntax_highlighting ) {
translate_rule_to_color ( edit , edit_get_rule ( edit , byte_index ) , fg , bg ) ;
} else {
1998-09-15 00:18:54 +04:00
# ifdef MIDNIGHT
1998-12-11 01:08:11 +03:00
* fg = EDITOR_NORMAL_COLOR ;
1998-09-15 00:18:54 +04:00
# 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 .
*/
static int read_one_line ( char * * line , FILE * f )
{
char * p ;
int len = 256 , c , r = 0 , i = 0 ;
p = syntax_malloc ( len ) ;
for ( ; ; ) {
c = fgetc ( f ) ;
if ( c = = - 1 ) {
1999-07-22 00:03:23 +04:00
if ( errno = = EINTR )
continue ;
1998-09-15 00:18:54 +04:00
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 ;
1999-07-22 00:03:23 +04:00
p = r = ( char * ) strdup ( s ) ;
1998-09-15 00:18:54 +04:00
while ( * s ) {
switch ( * s ) {
case ' \\ ' :
s + + ;
switch ( * s ) {
1998-12-10 18:43:32 +03:00
case ' ' :
* p = ' ' ;
s - - ;
break ;
1998-09-15 00:18:54 +04:00
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 ' ] ' :
1999-07-22 00:03:23 +04:00
* p = ' \003 ' ;
break ;
case ' { ' :
case ' } ' :
* p = ' \004 ' ;
1998-09-15 00:18:54 +04:00
break ;
default :
* p = * s ;
break ;
}
break ;
case ' * ' :
1999-07-22 00:03:23 +04:00
* p = ' \001 ' ;
1998-09-15 00:18:54 +04:00
break ;
case ' + ' :
1999-07-22 00:03:23 +04:00
* p = ' \002 ' ;
1998-09-15 00:18:54 +04:00
break ;
default :
* p = * s ;
break ;
}
s + + ;
p + + ;
}
1999-07-22 00:03:23 +04:00
* p = ' \0 ' ;
1998-09-15 00:18:54 +04:00
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
# endif
1999-03-21 04:56:20 +03:00
static char * error_file_name = 0 ;
static FILE * open_include_file ( char * filename )
{
FILE * f ;
char p [ MAX_PATH_LEN ] ;
syntax_free ( error_file_name ) ;
1999-07-22 00:03:23 +04:00
error_file_name = ( char * ) strdup ( filename ) ;
1999-03-21 04:56:20 +03:00
if ( * filename = = ' / ' )
return fopen ( filename , " r " ) ;
strcpy ( p , home_dir ) ;
strcat ( p , EDIT_DIR " / " ) ;
strcat ( p , filename ) ;
syntax_free ( error_file_name ) ;
1999-07-22 00:03:23 +04:00
error_file_name = ( char * ) strdup ( p ) ;
1999-03-21 04:56:20 +03:00
f = fopen ( p , " r " ) ;
if ( f )
return f ;
strcpy ( p , LIBDIR " /syntax/ " ) ;
strcat ( p , filename ) ;
syntax_free ( error_file_name ) ;
1999-07-22 00:03:23 +04:00
error_file_name = ( char * ) strdup ( p ) ;
1999-03-21 04:56:20 +03:00
return fopen ( p , " r " ) ;
}
1998-09-15 00:18:54 +04:00
/* returns line number on error */
static int edit_read_syntax_rules ( WEdit * edit , FILE * f )
{
1999-03-21 04:56:20 +03:00
FILE * g = 0 ;
1998-09-15 00:18:54 +04:00
char * fg , * bg ;
char last_fg [ 32 ] = " " , last_bg [ 32 ] = " " ;
1999-03-21 04:56:20 +03:00
char whole_right [ 512 ] ;
char whole_left [ 512 ] ;
1998-09-15 00:18:54 +04:00
char * args [ 1024 ] , * l = 0 ;
1999-03-21 04:56:20 +03:00
int save_line = 0 , line = 0 ;
1999-07-22 00:03:23 +04:00
struct context_rule * * r , * c = 0 ;
1998-09-15 00:18:54 +04:00
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 " ) ;
1999-07-22 00:03:23 +04:00
r = edit - > rules = syntax_malloc ( MAX_CONTEXTS * sizeof ( struct context_rule * ) ) ;
1998-09-15 00:18:54 +04:00
for ( ; ; ) {
char * * a ;
line + + ;
1999-03-21 04:56:20 +03:00
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 )
free ( l ) ;
if ( ! read_one_line ( & l , f ) )
break ;
} else {
break ;
}
}
1998-09-15 00:18:54 +04:00
get_args ( l , args , & argc ) ;
a = args + 1 ;
if ( ! args [ 0 ] ) {
/* do nothing */
1999-03-21 04:56:20 +03:00
} 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 ;
1998-09-15 00:18:54 +04:00
} 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 ) ) ;
1999-07-22 00:03:23 +04:00
c - > left = ( char * ) strdup ( " " ) ;
c - > right = ( char * ) strdup ( " " ) ;
1998-09-15 00:18:54 +04:00
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 + + ;
1999-07-22 00:03:23 +04:00
c - > whole_word_chars_left = ( char * ) strdup ( whole_left ) ;
c - > whole_word_chars_right = ( char * ) strdup ( whole_right ) ;
1998-09-15 00:18:54 +04:00
} else if ( ! strcmp ( * a , " wholeleft " ) ) {
a + + ;
1999-07-22 00:03:23 +04:00
c - > whole_word_chars_left = ( char * ) strdup ( whole_left ) ;
1998-09-15 00:18:54 +04:00
} else if ( ! strcmp ( * a , " wholeright " ) ) {
a + + ;
1999-07-22 00:03:23 +04:00
c - > whole_word_chars_right = ( char * ) strdup ( whole_right ) ;
1998-09-15 00:18:54 +04:00
}
check_a ;
if ( ! strcmp ( * a , " linestart " ) ) {
a + + ;
c - > line_start_left = 1 ;
}
check_a ;
1999-07-22 00:03:23 +04:00
c - > left = ( char * ) strdup ( * a + + ) ;
1998-09-15 00:18:54 +04:00
check_a ;
if ( ! strcmp ( * a , " linestart " ) ) {
a + + ;
c - > line_start_right = 1 ;
}
check_a ;
1999-07-22 00:03:23 +04:00
c - > right = ( char * ) strdup ( * a + + ) ;
1998-09-15 00:18:54 +04:00
c - > first_left = * c - > left ;
c - > first_right = * c - > right ;
c - > single_char = ( strlen ( c - > right ) = = 1 ) ;
}
1999-07-22 00:03:23 +04:00
c - > keyword = syntax_malloc ( MAX_WORDS_PER_CONTEXT * sizeof ( struct key_word * ) ) ;
#if 0
c - > max_words = MAX_WORDS_PER_CONTEXT ;
# endif
1998-09-15 00:18:54 +04:00
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
1999-07-22 00:03:23 +04:00
c - > keyword [ 0 ] - > keyword = ( char * ) strdup ( " " ) ;
1998-09-15 00:18:54 +04:00
check_not_a ;
num_contexts + + ;
1999-07-22 00:03:23 +04:00
} else if ( ! strcmp ( args [ 0 ] , " spellcheck " ) ) {
if ( ! c ) {
result = line ;
break ;
}
c - > spelling = 1 ;
1998-09-15 00:18:54 +04:00
} 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 + + ;
1999-07-22 00:03:23 +04:00
k - > whole_word_chars_left = ( char * ) strdup ( whole_left ) ;
k - > whole_word_chars_right = ( char * ) strdup ( whole_right ) ;
1998-09-15 00:18:54 +04:00
} else if ( ! strcmp ( * a , " wholeleft " ) ) {
a + + ;
1999-07-22 00:03:23 +04:00
k - > whole_word_chars_left = ( char * ) strdup ( whole_left ) ;
1998-09-15 00:18:54 +04:00
} else if ( ! strcmp ( * a , " wholeright " ) ) {
a + + ;
1999-07-22 00:03:23 +04:00
k - > whole_word_chars_right = ( char * ) strdup ( whole_right ) ;
1998-09-15 00:18:54 +04:00
}
check_a ;
if ( ! strcmp ( * a , " linestart " ) ) {
a + + ;
k - > line_start = 1 ;
}
check_a ;
if ( ! strcmp ( * a , " whole " ) ) {
* a = 0 ;
check_a ;
}
1999-07-22 00:03:23 +04:00
k - > keyword = ( char * ) strdup ( * a + + ) ;
1998-09-15 00:18:54 +04:00
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 ) ;
1999-07-22 00:03:23 +04:00
if ( ! edit - > rules [ 0 ] )
syntax_free ( edit - > rules ) ;
1998-09-15 00:18:54 +04:00
if ( result )
return result ;
if ( num_contexts = = - 1 ) {
result = line ;
return result ;
}
{
1999-07-22 00:03:23 +04:00
char first_chars [ MAX_WORDS_PER_CONTEXT + 2 ] , * p ;
1998-09-15 00:18:54 +04:00
for ( i = 0 ; edit - > rules [ i ] ; i + + ) {
c = edit - > rules [ i ] ;
p = first_chars ;
* p + + = ( char ) 1 ;
1999-07-22 00:03:23 +04:00
for ( j = 1 ; c - > keyword [ j ] ; j + + )
1998-09-15 00:18:54 +04:00
* p + + = c - > keyword [ j ] - > first ;
* p = ' \0 ' ;
1999-07-22 00:03:23 +04:00
c - > keyword_first_chars = malloc ( strlen ( first_chars ) + 2 ) ;
strcpy ( c - > keyword_first_chars , first_chars ) ;
1998-09-15 00:18:54 +04:00
}
}
return result ;
}
1999-07-22 00:03:23 +04:00
# if !defined (GTK) && !defined (MIDNIGHT)
/* strdup and append c */
static char * strdupc ( char * s , int c )
{
char * t ;
int l ;
strcpy ( t = 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 - - ;
free ( c - > keyword [ j ] - > keyword ) ;
free ( c - > keyword [ j ] - > whole_word_chars_left ) ;
free ( c - > keyword [ j ] - > whole_word_chars_right ) ;
free ( c - > keyword [ j ] ) ;
memcpy ( & c - > keyword [ j ] , & c - > keyword [ j + 1 ] , ( MAX_WORDS_PER_CONTEXT - j ) * 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 - 1 )
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 ) ;
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 = 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 */
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 ;
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 ) {
free ( q ) ;
return 1 ;
}
if ( r = = ' \n ' ) { /* ispell sometimes returns just blank line if it is given bad characters */
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 ) {
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 = = ' - ' ) {
free ( q ) ;
return 0 ;
}
/* not spelled ok - so add a syntax keyword for this word */
edit_syntax_add_keyword ( edit , ( char * ) q , context , t ) ;
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
1998-09-15 00:18:54 +04:00
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 ;
1999-07-22 00:03:23 +04:00
edit_get_rule ( edit , - 1 ) ;
1998-09-15 00:18:54 +04:00
syntax_free ( edit - > syntax_type ) ;
1998-12-10 18:43:32 +03:00
edit - > syntax_type = 0 ;
1998-09-15 00:18:54 +04:00
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 ] ) ;
}
1998-12-10 18:43:32 +03:00
for ( ; ; ) {
struct _syntax_marker * s ;
if ( ! edit - > syntax_marker )
break ;
s = edit - > syntax_marker - > next ;
syntax_free ( edit - > syntax_marker ) ;
edit - > syntax_marker = s ;
}
1998-09-15 00:18:54 +04:00
syntax_free ( edit - > rules ) ;
}
1999-07-22 00:03:23 +04:00
# define CURRENT_SYNTAX_RULES_VERSION "61"
1998-09-15 00:18:54 +04:00
1998-12-10 18:43:32 +03:00
char * 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 " ,
" " ,
1999-03-21 04:56:20 +03:00
" file gobledy_gook # \\ sHelp \\ ssupport \\ sother \\ sfile \\ stypes " ,
1998-12-10 18:43:32 +03:00
" context default " ,
1999-03-21 04:56:20 +03:00
" file gobledy_gook # \\ sby \\ scoding \\ srules \\ sin \\ s~/.cedit/syntax. " ,
1998-12-10 18:43:32 +03:00
" context default " ,
1999-03-21 04:56:20 +03:00
" file gobledy_gook # \\ sSee \\ sman/syntax \\ sin \\ sthe \\ ssource \\ sdistribution " ,
1998-12-10 18:43:32 +03:00
" context default " ,
1999-03-21 04:56:20 +03:00
" file gobledy_gook # \\ sand \\ sconsult \\ sthe \\ sman \\ spage. " ,
1998-12-10 18:43:32 +03:00
" context default " ,
" " ,
" " ,
1999-03-21 04:56:20 +03:00
" file .. \\ * \\ \\ .diff$ Unified \\ sDiff \\ sOutput ^diff. \\ *(-u|--unified) " ,
" include diff.syntax " ,
1998-12-10 18:43:32 +03:00
" " ,
1999-03-21 04:56:20 +03:00
" file .. \\ * \\ \\ .diff$ Context \\ sDiff \\ sOutput ^diff. \\ *(-c|--context) " ,
" include diffc.syntax " ,
1998-12-10 18:43:32 +03:00
" " ,
1999-03-21 04:56:20 +03:00
" file .. \\ * \\ \\ .lsm$ LSM \\ sFile " ,
" include lsm.syntax " ,
1998-12-10 18:43:32 +03:00
" " ,
1999-07-22 00:03:23 +04:00
" file .. \\ * \\ \\ .sh$ Shell \\ sScript ^#! \\ s \\ */. \\ */(ksh|bash|sh|pdkzsh) " ,
1999-03-21 04:56:20 +03:00
" include sh.syntax " ,
1998-12-10 18:43:32 +03:00
" " ,
1999-07-22 00:03:23 +04:00
" file .. \\ * \\ \\ .(pl|PL])$ Perl \\ sProgram ^#! \\ s \\ */. \\ */perl " ,
1999-03-21 04:56:20 +03:00
" include perl.syntax " ,
1998-12-10 18:43:32 +03:00
" " ,
1999-07-22 00:03:23 +04:00
" file .. \\ * \\ \\ .(py|PY])$ Python \\ sProgram ^#! \\ s \\ */. \\ */python " ,
1999-03-21 04:56:20 +03:00
" include python.syntax " ,
1998-12-10 18:43:32 +03:00
" " ,
" file .. \\ * \\ \\ .(man|[0-9n]|[0-9]x)$ NROFF \\ sSource " ,
1999-03-21 04:56:20 +03:00
" include nroff.syntax " ,
1998-12-10 18:43:32 +03:00
" " ,
" file .. \\ * \\ \\ .(htm|html|HTM|HTML)$ HTML \\ sFile " ,
1999-03-21 04:56:20 +03:00
" include html.syntax " ,
1998-12-10 18:43:32 +03:00
" " ,
1999-07-22 00:03:23 +04:00
" file .. \\ * \\ \\ .(pp|PP|pas|PAS)$ Pascal \\ sProgram " ,
1999-03-21 04:56:20 +03:00
" include pascal.syntax " ,
1998-12-10 18:43:32 +03:00
" " ,
1999-07-22 00:03:23 +04:00
" file .. \\ * \\ \\ .(ada|adb|ADA|ADB)$ Ada \\ sProgram " ,
" include ada95.syntax " ,
" " ,
1998-12-10 18:43:32 +03:00
" file .. \\ * \\ \\ .tex$ LaTeX \\ s2.09 \\ sDocument " ,
1999-03-21 04:56:20 +03:00
" include latex.syntax " ,
1998-12-10 18:43:32 +03:00
" " ,
1999-07-22 00:03:23 +04:00
" file .. \\ * \\ .(texi|texinfo|TEXI|TEXINFO)$ Texinfo \\ sDocument " ,
" include texinfo.syntax " ,
" " ,
1998-12-10 18:43:32 +03:00
" file .. \\ * \\ \\ .([chC]|CC|cxx|cc|cpp|CPP|CXX)$ C/C \\ + \\ + \\ sProgram " ,
1999-03-21 04:56:20 +03:00
" include c.syntax " ,
1998-12-10 18:43:32 +03:00
" " ,
1999-07-22 00:03:23 +04:00
" file .. \\ * \\ \\ .i$ SWIG \\ sSource " ,
" include swig.syntax " ,
" " ,
1999-03-21 04:56:20 +03:00
" file .. \\ * \\ \\ .(java|JAVA|Java|jav)$ Java \\ sProgram " ,
" include java.syntax " ,
1998-12-10 18:43:32 +03:00
" " ,
1999-03-21 04:56:20 +03:00
" file .. \\ * \\ \\ .(st)$ SmallTalk \\ sProgram " ,
" include smalltalk.syntax " ,
1998-12-10 18:43:32 +03:00
" " ,
1999-03-21 04:56:20 +03:00
" file .. \\ * \\ \\ .(ml|mli|mly|mll|mlp)$ ML \\ sProgram " ,
" include ml.syntax " ,
1998-12-10 18:43:32 +03:00
" " ,
1999-03-21 04:56:20 +03:00
" file . \\ *ChangeLog$ GNU \\ sDistribution \\ sChangeLog \\ sFile " ,
" include changelog.syntax " ,
1998-12-10 18:43:32 +03:00
" " ,
" file . \\ *Makefile[ \\ \\ \\ .a-z] \\ *$ Makefile " ,
1999-03-21 04:56:20 +03:00
" include makefile.syntax " ,
1998-12-10 18:43:32 +03:00
" " ,
1999-07-22 00:03:23 +04:00
" file Don_t_match_me Mail \\ sfolder ^From \\ s " ,
" include mail.syntax " ,
" " ,
1998-12-10 18:43:32 +03:00
" file . \\ *syntax$ Syntax \\ sHighlighting \\ sdefinitions " ,
" " ,
" context default " ,
1999-07-22 00:03:23 +04:00
" keyword whole spellch \\ eck yellow/24 " ,
1998-12-10 18:43:32 +03:00
" 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 " ,
1999-03-21 04:56:20 +03:00
" keyword whole in \\ clude brightred/18 " ,
1998-12-10 18:43:32 +03:00
" " ,
" 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 " ,
" " ,
1999-07-22 00:03:23 +04:00
" file . \\ * " UNKNOWN_FORMAT ,
" include unknown.syntax " ,
" " ,
1998-12-10 18:43:32 +03:00
0 } ;
1998-09-15 00:18:54 +04:00
FILE * upgrade_syntax_file ( char * syntax_file )
{
FILE * f ;
1999-07-22 00:03:23 +04:00
char * p ;
1998-09-15 00:18:54 +04:00
char line [ 80 ] ;
f = fopen ( syntax_file , " r " ) ;
if ( ! f ) {
1998-12-10 18:43:32 +03:00
char * * syntax_line ;
1998-09-15 00:18:54 +04:00
f = fopen ( syntax_file , " w " ) ;
if ( ! f )
return 0 ;
1998-12-10 18:43:32 +03:00
for ( syntax_line = syntax_text ; * syntax_line ; syntax_line + + )
fprintf ( f , " %s \n " , * syntax_line ) ;
1998-09-15 00:18:54 +04:00
fclose ( f ) ;
return fopen ( syntax_file , " r " ) ;
}
memset ( line , 0 , 79 ) ;
fread ( line , 80 , 1 , f ) ;
1999-07-22 00:03:23 +04:00
if ( ! strstr ( line , " syntax rules version " ) )
1998-09-15 00:18:54 +04:00
goto rename_rule_file ;
1999-07-22 00:03:23 +04:00
p = strstr ( line , " version " ) + strlen ( " version " ) + 1 ;
if ( atoi ( p ) < atoi ( CURRENT_SYNTAX_RULES_VERSION ) ) {
char s [ 1024 ] ;
rename_rule_file :
strcpy ( s , syntax_file ) ;
strcat ( s , " .OLD " ) ;
unlink ( s ) ;
rename ( syntax_file , s ) ;
unlink ( syntax_file ) ; /* might rename() fail ? */
1998-09-15 00:18:54 +04:00
# if defined(MIDNIGHT) || defined(GTK)
1999-07-22 00:03:23 +04:00
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. " ) ;
1998-09-15 00:18:54 +04:00
# else
1999-07-22 00:03:23 +04:00
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. " ) ;
1998-09-15 00:18:54 +04:00
# endif
1999-07-22 00:03:23 +04:00
return upgrade_syntax_file ( syntax_file ) ;
1998-09-15 00:18:54 +04:00
}
1999-07-22 00:03:23 +04:00
rewind ( f ) ;
return f ;
1998-09-15 00:18:54 +04:00
}
/* 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 , r2 ;
regmatch_t pmatch [ 1 ] ;
char * args [ 1024 ] , * l ;
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 + + ;
if ( ! read_one_line ( & l , f ) )
break ;
get_args ( l , args , & argc ) ;
if ( ! args [ 0 ] ) {
} else if ( ! strcmp ( args [ 0 ] , " file " ) ) {
if ( ! args [ 1 ] | | ! args [ 2 ] ) {
result = line ;
break ;
}
if ( regcomp ( & r , args [ 1 ] , REG_EXTENDED ) ) {
result = line ;
break ;
}
if ( regcomp ( & r2 , args [ 3 ] ? args [ 3 ] : " ^nEvEr MaTcH aNyThInG$ " , REG_EXTENDED ) ) {
result = line ;
break ;
}
if ( names ) {
1999-07-22 00:03:23 +04:00
names [ count + + ] = ( char * ) strdup ( args [ 2 ] ) ;
1998-09-15 00:18:54 +04:00
names [ count ] = 0 ;
} else if ( type ) {
if ( ! strcmp ( type , args [ 2 ] ) )
goto found_type ;
} else if ( editor_file & & edit ) {
if ( ! regexec ( & r , editor_file , 1 , pmatch , 0 ) | | ! regexec ( & r2 , first_line , 1 , pmatch , 0 ) ) {
int line_error ;
found_type :
line_error = edit_read_syntax_rules ( edit , f ) ;
1999-03-21 04:56:20 +03:00
if ( line_error ) {
if ( ! error_file_name ) /* an included file */
result = line + line_error ;
else
result = line_error ;
} else {
1998-09-15 00:18:54 +04:00
syntax_free ( edit - > syntax_type ) ;
1999-07-22 00:03:23 +04:00
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 ;
}
1998-09-15 00:18:54 +04:00
if ( syntax_change_callback )
# ifdef MIDNIGHT
( * syntax_change_callback ) ( & edit - > widget ) ;
# else
( * syntax_change_callback ) ( edit - > widget ) ;
# endif
}
break ;
}
}
}
free_args ( args ) ;
syntax_free ( l ) ;
}
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 ) ;
# ifdef MIDNIGHT
1998-12-11 01:08:11 +03:00
if ( ! SLtt_Use_Ansi_Colors | | ! use_colors )
1998-09-15 00:18:54 +04:00
return ;
# endif
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 ) ;
1999-03-21 04:56:20 +03:00
sprintf ( s , _ ( " Error in file %s on line %d " ) , error_file_name ? error_file_name : f , r ) ;
1998-09-15 00:18:54 +04:00
edit_error_dialog ( _ ( " Load syntax file " ) , s ) ;
1999-03-21 04:56:20 +03:00
syntax_free ( error_file_name ) ;
1998-09-15 00:18:54 +04:00
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 ;
}
# endif /* !defined(MIDNIGHT) || defined(HAVE_SYNTAXH) */
1999-03-21 04:56:20 +03:00