root/src/editor/syntax.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. syntax_keyword_free
  2. context_rule_free
  3. mc_defines_destroy
  4. destroy_defines
  5. xx_tolower
  6. subst_defines
  7. compare_word_to_right
  8. xx_strchr
  9. apply_rules_going_right
  10. edit_get_rule
  11. translate_rule_to_color
  12. read_one_line
  13. convert
  14. get_args
  15. this_try_alloc_color_pair
  16. open_include_file
  17. xx_lowerize_line
  18. edit_read_syntax_rules
  19. edit_read_syntax_file
  20. get_first_editor_line
  21. edit_get_syntax_color
  22. edit_free_syntax_rules
  23. edit_load_syntax
  24. edit_get_syntax_type

   1 /*
   2    Editor syntax highlighting.
   3 
   4    Copyright (C) 1996-2019
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Paul Sheer, 1998
   9    Egmont Koblinger <egmont@gmail.com>, 2010
  10    Slava Zanko <slavazanko@gmail.com>, 2013
  11    Andrew Borodin <aborodin@vmail.ru>, 2013, 2014
  12 
  13    This file is part of the Midnight Commander.
  14 
  15    The Midnight Commander is free software: you can redistribute it
  16    and/or modify it under the terms of the GNU General Public License as
  17    published by the Free Software Foundation, either version 3 of the License,
  18    or (at your option) any later version.
  19 
  20    The Midnight Commander is distributed in the hope that it will be useful,
  21    but WITHOUT ANY WARRANTY; without even the implied warranty of
  22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23    GNU General Public License for more details.
  24 
  25    You should have received a copy of the GNU General Public License
  26    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  27  */
  28 
  29 /** \file
  30  *  \brief Source: editor syntax highlighting
  31  *  \author Paul Sheer
  32  *  \date 1996, 1997
  33  *  \author Mikhail Pobolovets
  34  *  \date 2010
  35  *
  36  *  Mispelled words are flushed from the syntax highlighting rules
  37  *  when they have been around longer than
  38  *  TRANSIENT_WORD_TIME_OUT seconds. At a cursor rate of 30
  39  *  chars per second and say 3 chars + a space per word, we can
  40  *  accumulate 450 words absolute max with a value of 60. This is
  41  *  below this limit of 1024 words in a context.
  42  */
  43 
  44 #include <config.h>
  45 
  46 #include <stdio.h>
  47 #include <stdarg.h>
  48 #include <sys/types.h>
  49 #include <unistd.h>
  50 #include <string.h>
  51 #include <ctype.h>
  52 #include <errno.h>
  53 #include <sys/stat.h>
  54 #include <stdlib.h>
  55 
  56 #include "lib/global.h"
  57 #include "lib/search.h"         /* search engine */
  58 #include "lib/skin.h"
  59 #include "lib/fileloc.h"        /* EDIT_DIR, EDIT_SYNTAX_FILE */
  60 #include "lib/strutil.h"        /* utf string functions */
  61 #include "lib/util.h"
  62 #include "lib/widget.h"         /* message() */
  63 
  64 #include "edit-impl.h"
  65 #include "editwidget.h"
  66 
  67 /*** global variables ****************************************************************************/
  68 
  69 gboolean option_syntax_highlighting = TRUE;
  70 gboolean option_auto_syntax = TRUE;
  71 
  72 /*** file scope macro definitions ****************************************************************/
  73 
  74 /* bytes */
  75 #define SYNTAX_MARKER_DENSITY 512
  76 
  77 #define RULE_ON_LEFT_BORDER 1
  78 #define RULE_ON_RIGHT_BORDER 2
  79 
  80 #define SYNTAX_TOKEN_STAR       '\001'
  81 #define SYNTAX_TOKEN_PLUS       '\002'
  82 #define SYNTAX_TOKEN_BRACKET    '\003'
  83 #define SYNTAX_TOKEN_BRACE      '\004'
  84 
  85 #define break_a { result = line; break; }
  86 #define check_a { if (*a == NULL) { result = line; break; } }
  87 #define check_not_a { if (*a != NULL) { result = line ;break; } }
  88 
  89 #define SYNTAX_KEYWORD(x) ((syntax_keyword_t *) (x))
  90 #define CONTEXT_RULE(x) ((context_rule_t *) (x))
  91 
  92 #define ARGS_LEN 1024
  93 
  94 /*** file scope type declarations ****************************************************************/
  95 
  96 typedef struct
  97 {
  98     char *keyword;
  99     char *whole_word_chars_left;
 100     char *whole_word_chars_right;
 101     gboolean line_start;
 102     int color;
 103 } syntax_keyword_t;
 104 
 105 typedef struct
 106 {
 107     char *left;
 108     unsigned char first_left;
 109     char *right;
 110     unsigned char first_right;
 111     gboolean line_start_left;
 112     gboolean line_start_right;
 113     gboolean between_delimiters;
 114     char *whole_word_chars_left;
 115     char *whole_word_chars_right;
 116     char *keyword_first_chars;
 117     gboolean spelling;
 118     /* first word is word[1] */
 119     GPtrArray *keyword;
 120 } context_rule_t;
 121 
 122 typedef struct
 123 {
 124     off_t offset;
 125     edit_syntax_rule_t rule;
 126 } syntax_marker_t;
 127 
 128 /*** file scope variables ************************************************************************/
 129 
 130 static char *error_file_name = NULL;
 131 
 132 /* --------------------------------------------------------------------------------------------- */
 133 /*** file scope functions ************************************************************************/
 134 /* --------------------------------------------------------------------------------------------- */
 135 
 136 static void
 137 syntax_keyword_free (gpointer keyword)
     /* [previous][next][first][last][top][bottom][index][help]  */
 138 {
 139     syntax_keyword_t *k = SYNTAX_KEYWORD (keyword);
 140 
 141     g_free (k->keyword);
 142     g_free (k->whole_word_chars_left);
 143     g_free (k->whole_word_chars_right);
 144     g_free (k);
 145 }
 146 
 147 /* --------------------------------------------------------------------------------------------- */
 148 
 149 static void
 150 context_rule_free (gpointer rule)
     /* [previous][next][first][last][top][bottom][index][help]  */
 151 {
 152     context_rule_t *r = CONTEXT_RULE (rule);
 153 
 154     g_free (r->left);
 155     g_free (r->right);
 156     g_free (r->whole_word_chars_left);
 157     g_free (r->whole_word_chars_right);
 158     g_free (r->keyword_first_chars);
 159 
 160     if (r->keyword != NULL)
 161     {
 162         g_ptr_array_foreach (r->keyword, (GFunc) syntax_keyword_free, NULL);
 163         g_ptr_array_free (r->keyword, TRUE);
 164     }
 165 
 166     g_free (r);
 167 }
 168 
 169 /* --------------------------------------------------------------------------------------------- */
 170 
 171 static gint
 172 mc_defines_destroy (gpointer key, gpointer value, gpointer data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 173 {
 174     (void) data;
 175 
 176     g_free (key);
 177     g_strfreev ((char **) value);
 178 
 179     return FALSE;
 180 }
 181 
 182 /* --------------------------------------------------------------------------------------------- */
 183 /** Completely destroys the defines tree */
 184 
 185 static void
 186 destroy_defines (GTree ** defines)
     /* [previous][next][first][last][top][bottom][index][help]  */
 187 {
 188     g_tree_foreach (*defines, mc_defines_destroy, NULL);
 189     g_tree_destroy (*defines);
 190     *defines = NULL;
 191 }
 192 
 193 /* --------------------------------------------------------------------------------------------- */
 194 
 195 /** Wrapper for case insensitive mode */
 196 inline static int
 197 xx_tolower (const WEdit * edit, int c)
     /* [previous][next][first][last][top][bottom][index][help]  */
 198 {
 199     return edit->is_case_insensitive ? tolower (c) : c;
 200 }
 201 
 202 /* --------------------------------------------------------------------------------------------- */
 203 
 204 static void
 205 subst_defines (GTree * defines, char **argv, char **argv_end)
     /* [previous][next][first][last][top][bottom][index][help]  */
 206 {
 207     for (; *argv != NULL && argv < argv_end; argv++)
 208     {
 209         char **t;
 210 
 211         t = g_tree_lookup (defines, *argv);
 212         if (t != NULL)
 213         {
 214             int argc, count;
 215             char **p;
 216 
 217             /* Count argv array members */
 218             argc = g_strv_length (argv + 1);
 219 
 220             /* Count members of definition array */
 221             count = g_strv_length (t);
 222 
 223             p = argv + count + argc;
 224             /* Buffer overflow or infinitive loop in define */
 225             if (p >= argv_end)
 226                 break;
 227 
 228             /* Move rest of argv after definition members */
 229             while (argc >= 0)
 230                 *p-- = argv[argc-- + 1];
 231 
 232             /* Copy definition members to argv */
 233             for (p = argv; *t != NULL; *p++ = *t++)
 234                 ;
 235         }
 236     }
 237 }
 238 
 239 /* --------------------------------------------------------------------------------------------- */
 240 
 241 static off_t
 242 compare_word_to_right (const WEdit * edit, off_t i, const char *text,
     /* [previous][next][first][last][top][bottom][index][help]  */
 243                        const char *whole_left, const char *whole_right, gboolean line_start)
 244 {
 245     const unsigned char *p, *q;
 246     int c, d, j;
 247 
 248     if (*text == '\0')
 249         return -1;
 250 
 251     c = xx_tolower (edit, edit_buffer_get_byte (&edit->buffer, i - 1));
 252     if ((line_start && c != '\n') || (whole_left != NULL && strchr (whole_left, c) != NULL))
 253         return -1;
 254 
 255     for (p = (const unsigned char *) text, q = p + strlen ((const char *) p); p < q; p++, i++)
 256     {
 257         switch (*p)
 258         {
 259         case SYNTAX_TOKEN_STAR:
 260             if (++p > q)
 261                 return -1;
 262             while (TRUE)
 263             {
 264                 c = xx_tolower (edit, edit_buffer_get_byte (&edit->buffer, i));
 265                 if (*p == '\0' && whole_right != NULL && strchr (whole_right, c) == NULL)
 266                     break;
 267                 if (c == *p)
 268                     break;
 269                 if (c == '\n')
 270                     return -1;
 271                 i++;
 272             }
 273             break;
 274         case SYNTAX_TOKEN_PLUS:
 275             if (++p > q)
 276                 return -1;
 277             j = 0;
 278             while (TRUE)
 279             {
 280                 c = xx_tolower (edit, edit_buffer_get_byte (&edit->buffer, i));
 281                 if (c == *p)
 282                 {
 283                     j = i;
 284                     if (p[0] == text[0] && p[1] == '\0')        /* handle eg '+' and @+@ keywords properly */
 285                         break;
 286                 }
 287                 if (j != 0 && strchr ((const char *) p + 1, c) != NULL) /* c exists further down, so it will get matched later */
 288                     break;
 289                 if (whiteness (c) || (whole_right != NULL && strchr (whole_right, c) == NULL))
 290                 {
 291                     if (*p == '\0')
 292                     {
 293                         i--;
 294                         break;
 295                     }
 296                     if (j == 0)
 297                         return -1;
 298                     i = j;
 299                     break;
 300                 }
 301                 i++;
 302             }
 303             break;
 304         case SYNTAX_TOKEN_BRACKET:
 305             if (++p > q)
 306                 return -1;
 307             c = -1;
 308             while (TRUE)
 309             {
 310                 d = c;
 311                 c = xx_tolower (edit, edit_buffer_get_byte (&edit->buffer, i));
 312                 for (j = 0; p[j] != SYNTAX_TOKEN_BRACKET && p[j] != '\0'; j++)
 313                     if (c == p[j])
 314                         goto found_char2;
 315                 break;
 316               found_char2:
 317                 i++;
 318             }
 319             i--;
 320             while (*p != SYNTAX_TOKEN_BRACKET && p <= q)
 321                 p++;
 322             if (p > q)
 323                 return -1;
 324             if (p[1] == d)
 325                 i--;
 326             break;
 327         case SYNTAX_TOKEN_BRACE:
 328             if (++p > q)
 329                 return -1;
 330             c = xx_tolower (edit, edit_buffer_get_byte (&edit->buffer, i));
 331             for (; *p != SYNTAX_TOKEN_BRACE && *p != '\0'; p++)
 332                 if (c == *p)
 333                     goto found_char3;
 334             return -1;
 335           found_char3:
 336             while (*p != SYNTAX_TOKEN_BRACE && p < q)
 337                 p++;
 338             break;
 339         default:
 340             if (*p != xx_tolower (edit, edit_buffer_get_byte (&edit->buffer, i)))
 341                 return -1;
 342         }
 343     }
 344     return (whole_right != NULL &&
 345             strchr (whole_right,
 346                     xx_tolower (edit, edit_buffer_get_byte (&edit->buffer, i))) != NULL) ? -1 : i;
 347 }
 348 
 349 /* --------------------------------------------------------------------------------------------- */
 350 
 351 static const char *
 352 xx_strchr (const WEdit * edit, const unsigned char *s, int char_byte)
     /* [previous][next][first][last][top][bottom][index][help]  */
 353 {
 354     while (*s >= '\005' && xx_tolower (edit, *s) != char_byte)
 355         s++;
 356 
 357     return (const char *) s;
 358 }
 359 
 360 /* --------------------------------------------------------------------------------------------- */
 361 
 362 static void
 363 apply_rules_going_right (WEdit * edit, off_t i)
     /* [previous][next][first][last][top][bottom][index][help]  */
 364 {
 365     context_rule_t *r;
 366     int c;
 367     gboolean contextchanged = FALSE;
 368     gboolean found_left = FALSE, found_right = FALSE;
 369     gboolean keyword_foundleft = FALSE, keyword_foundright = FALSE;
 370     gboolean is_end;
 371     off_t end = 0;
 372     edit_syntax_rule_t _rule = edit->rule;
 373 
 374     c = xx_tolower (edit, edit_buffer_get_byte (&edit->buffer, i));
 375     if (c == 0)
 376         return;
 377 
 378     is_end = (edit->rule.end == i);
 379 
 380     /* check to turn off a keyword */
 381     if (_rule.keyword != 0)
 382     {
 383         if (edit_buffer_get_byte (&edit->buffer, i - 1) == '\n')
 384             _rule.keyword = 0;
 385         if (is_end)
 386         {
 387             _rule.keyword = 0;
 388             keyword_foundleft = TRUE;
 389         }
 390     }
 391 
 392     /* check to turn off a context */
 393     if (_rule.context != 0 && _rule.keyword == 0)
 394     {
 395         off_t e;
 396 
 397         r = CONTEXT_RULE (g_ptr_array_index (edit->rules, _rule.context));
 398         if (r->first_right == c && (edit->rule.border & RULE_ON_RIGHT_BORDER) == 0
 399             && (e =
 400                 compare_word_to_right (edit, i, r->right, r->whole_word_chars_left,
 401                                        r->whole_word_chars_right, r->line_start_right)) > 0)
 402         {
 403             _rule.end = e;
 404             found_right = TRUE;
 405             _rule.border = RULE_ON_RIGHT_BORDER;
 406             if (r->between_delimiters)
 407                 _rule.context = 0;
 408         }
 409         else if (is_end && (edit->rule.border & RULE_ON_RIGHT_BORDER) != 0)
 410         {
 411             /* always turn off a context at 4 */
 412             found_left = TRUE;
 413             _rule.border = 0;
 414             if (!keyword_foundleft)
 415                 _rule.context = 0;
 416         }
 417         else if (is_end && (edit->rule.border & RULE_ON_LEFT_BORDER) != 0)
 418         {
 419             /* never turn off a context at 2 */
 420             found_left = TRUE;
 421             _rule.border = 0;
 422         }
 423     }
 424 
 425     /* check to turn on a keyword */
 426     if (_rule.keyword == 0)
 427     {
 428         const char *p;
 429 
 430         r = CONTEXT_RULE (g_ptr_array_index (edit->rules, _rule.context));
 431         p = r->keyword_first_chars;
 432 
 433         if (p != NULL)
 434             while (*(p = xx_strchr (edit, (const unsigned char *) p + 1, c)) != '\0')
 435             {
 436                 syntax_keyword_t *k;
 437                 int count;
 438                 off_t e;
 439 
 440                 count = p - r->keyword_first_chars;
 441                 k = SYNTAX_KEYWORD (g_ptr_array_index (r->keyword, count));
 442                 e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left,
 443                                            k->whole_word_chars_right, k->line_start);
 444                 if (e > 0)
 445                 {
 446                     /* when both context and keyword terminate with a newline,
 447                        the context overflows to the next line and colorizes it incorrectly */
 448                     if (e > i + 1 && _rule._context != 0
 449                         && k->keyword[strlen (k->keyword) - 1] == '\n')
 450                     {
 451                         r = CONTEXT_RULE (g_ptr_array_index (edit->rules, _rule._context));
 452                         if (r->right != NULL && r->right[0] != '\0'
 453                             && r->right[strlen (r->right) - 1] == '\n')
 454                             e--;
 455                     }
 456 
 457                     end = e;
 458                     _rule.end = e;
 459                     _rule.keyword = count;
 460                     keyword_foundright = TRUE;
 461                     break;
 462                 }
 463             }
 464     }
 465 
 466     /* check to turn on a context */
 467     if (_rule.context == 0)
 468     {
 469         if (!found_left && is_end)
 470         {
 471             if ((edit->rule.border & RULE_ON_RIGHT_BORDER) != 0)
 472             {
 473                 _rule.border = 0;
 474                 _rule.context = 0;
 475                 contextchanged = TRUE;
 476                 _rule.keyword = 0;
 477 
 478             }
 479             else if ((edit->rule.border & RULE_ON_LEFT_BORDER) != 0)
 480             {
 481                 r = CONTEXT_RULE (g_ptr_array_index (edit->rules, _rule._context));
 482                 _rule.border = 0;
 483                 if (r->between_delimiters)
 484                 {
 485                     _rule.context = _rule._context;
 486                     contextchanged = TRUE;
 487                     _rule.keyword = 0;
 488 
 489                     if (r->first_right == c)
 490                     {
 491                         off_t e;
 492 
 493                         e = compare_word_to_right (edit, i, r->right, r->whole_word_chars_left,
 494                                                    r->whole_word_chars_right, r->line_start_right);
 495                         if (e >= end)
 496                         {
 497                             _rule.end = e;
 498                             found_right = TRUE;
 499                             _rule.border = RULE_ON_RIGHT_BORDER;
 500                             _rule.context = 0;
 501                         }
 502                     }
 503                 }
 504             }
 505         }
 506 
 507         if (!found_right)
 508         {
 509             size_t count;
 510 
 511             for (count = 1; count < edit->rules->len; count++)
 512             {
 513                 r = CONTEXT_RULE (g_ptr_array_index (edit->rules, count));
 514                 if (r->first_left == c)
 515                 {
 516                     off_t e;
 517 
 518                     e = compare_word_to_right (edit, i, r->left, r->whole_word_chars_left,
 519                                                r->whole_word_chars_right, r->line_start_left);
 520                     if (e >= end && (_rule.keyword == 0 || keyword_foundright))
 521                     {
 522                         _rule.end = e;
 523                         found_right = TRUE;
 524                         _rule.border = RULE_ON_LEFT_BORDER;
 525                         _rule._context = count;
 526                         if (!r->between_delimiters && _rule.keyword == 0)
 527                         {
 528                             _rule.context = count;
 529                             contextchanged = TRUE;
 530                         }
 531                         break;
 532                     }
 533                 }
 534             }
 535         }
 536     }
 537 
 538     /* check again to turn on a keyword if the context switched */
 539     if (contextchanged && _rule.keyword == 0)
 540     {
 541         const char *p;
 542 
 543         r = CONTEXT_RULE (g_ptr_array_index (edit->rules, _rule.context));
 544         p = r->keyword_first_chars;
 545 
 546         while (*(p = xx_strchr (edit, (const unsigned char *) p + 1, c)) != '\0')
 547         {
 548             syntax_keyword_t *k;
 549             int count;
 550             off_t e;
 551 
 552             count = p - r->keyword_first_chars;
 553             k = SYNTAX_KEYWORD (g_ptr_array_index (r->keyword, count));
 554             e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left,
 555                                        k->whole_word_chars_right, k->line_start);
 556             if (e > 0)
 557             {
 558                 _rule.end = e;
 559                 _rule.keyword = count;
 560                 break;
 561             }
 562         }
 563     }
 564 
 565     edit->rule = _rule;
 566 }
 567 
 568 /* --------------------------------------------------------------------------------------------- */
 569 
 570 static void
 571 edit_get_rule (WEdit * edit, off_t byte_index)
     /* [previous][next][first][last][top][bottom][index][help]  */
 572 {
 573     off_t i;
 574 
 575     if (byte_index > edit->last_get_rule)
 576     {
 577         for (i = edit->last_get_rule + 1; i <= byte_index; i++)
 578         {
 579             off_t d = SYNTAX_MARKER_DENSITY;
 580 
 581             apply_rules_going_right (edit, i);
 582 
 583             if (edit->syntax_marker != NULL)
 584                 d += ((syntax_marker_t *) edit->syntax_marker->data)->offset;
 585 
 586             if (i > d)
 587             {
 588                 syntax_marker_t *s;
 589 
 590                 s = g_new (syntax_marker_t, 1);
 591                 s->offset = i;
 592                 s->rule = edit->rule;
 593                 edit->syntax_marker = g_slist_prepend (edit->syntax_marker, s);
 594             }
 595         }
 596     }
 597     else if (byte_index < edit->last_get_rule)
 598     {
 599         while (TRUE)
 600         {
 601             syntax_marker_t *s;
 602 
 603             if (edit->syntax_marker == NULL)
 604             {
 605                 memset (&edit->rule, 0, sizeof (edit->rule));
 606                 for (i = -1; i <= byte_index; i++)
 607                     apply_rules_going_right (edit, i);
 608                 break;
 609             }
 610 
 611             s = (syntax_marker_t *) edit->syntax_marker->data;
 612 
 613             if (byte_index >= s->offset)
 614             {
 615                 edit->rule = s->rule;
 616                 for (i = s->offset + 1; i <= byte_index; i++)
 617                     apply_rules_going_right (edit, i);
 618                 break;
 619             }
 620 
 621             g_free (s);
 622             edit->syntax_marker = g_slist_delete_link (edit->syntax_marker, edit->syntax_marker);
 623         }
 624     }
 625     edit->last_get_rule = byte_index;
 626 }
 627 
 628 /* --------------------------------------------------------------------------------------------- */
 629 
 630 static int
 631 translate_rule_to_color (const WEdit * edit, const edit_syntax_rule_t * rule)
     /* [previous][next][first][last][top][bottom][index][help]  */
 632 {
 633     syntax_keyword_t *k;
 634     context_rule_t *r;
 635 
 636     r = CONTEXT_RULE (g_ptr_array_index (edit->rules, rule->context));
 637     k = SYNTAX_KEYWORD (g_ptr_array_index (r->keyword, rule->keyword));
 638 
 639     return k->color;
 640 }
 641 
 642 /* --------------------------------------------------------------------------------------------- */
 643 /**
 644    Returns 0 on error/eof or a count of the number of bytes read
 645    including the newline. Result must be free'd.
 646    In case of an error, *line will not be modified.
 647  */
 648 
 649 static size_t
 650 read_one_line (char **line, FILE * f)
     /* [previous][next][first][last][top][bottom][index][help]  */
 651 {
 652     GString *p;
 653     size_t r = 0;
 654 
 655     /* not reallocate string too often */
 656     p = g_string_sized_new (64);
 657 
 658     while (TRUE)
 659     {
 660         int c;
 661 
 662         c = fgetc (f);
 663         if (c == EOF)
 664         {
 665             if (ferror (f))
 666             {
 667                 if (errno == EINTR)
 668                     continue;
 669                 r = 0;
 670             }
 671             break;
 672         }
 673         r++;
 674 
 675         /* handle all of \r\n, \r, \n correctly. */
 676         if (c == '\n')
 677             break;
 678         if (c == '\r')
 679         {
 680             c = fgetc (f);
 681             if (c == '\n')
 682                 r++;
 683             else
 684                 ungetc (c, f);
 685             break;
 686         }
 687 
 688         g_string_append_c (p, c);
 689     }
 690     if (r != 0)
 691         *line = g_string_free (p, FALSE);
 692     else
 693         g_string_free (p, TRUE);
 694 
 695     return r;
 696 }
 697 
 698 /* --------------------------------------------------------------------------------------------- */
 699 
 700 static char *
 701 convert (char *s)
     /* [previous][next][first][last][top][bottom][index][help]  */
 702 {
 703     char *r, *p;
 704 
 705     p = r = s;
 706     while (*s)
 707     {
 708         switch (*s)
 709         {
 710         case '\\':
 711             s++;
 712             switch (*s)
 713             {
 714             case ' ':
 715                 *p = ' ';
 716                 s--;
 717                 break;
 718             case 'n':
 719                 *p = '\n';
 720                 break;
 721             case 'r':
 722                 *p = '\r';
 723                 break;
 724             case 't':
 725                 *p = '\t';
 726                 break;
 727             case 's':
 728                 *p = ' ';
 729                 break;
 730             case '*':
 731                 *p = '*';
 732                 break;
 733             case '\\':
 734                 *p = '\\';
 735                 break;
 736             case '[':
 737             case ']':
 738                 *p = SYNTAX_TOKEN_BRACKET;
 739                 break;
 740             case '{':
 741             case '}':
 742                 *p = SYNTAX_TOKEN_BRACE;
 743                 break;
 744             case 0:
 745                 *p = *s;
 746                 return r;
 747             default:
 748                 *p = *s;
 749                 break;
 750             }
 751             break;
 752         case '*':
 753             *p = SYNTAX_TOKEN_STAR;
 754             break;
 755         case '+':
 756             *p = SYNTAX_TOKEN_PLUS;
 757             break;
 758         default:
 759             *p = *s;
 760             break;
 761         }
 762         s++;
 763         p++;
 764     }
 765     *p = '\0';
 766     return r;
 767 }
 768 
 769 /* --------------------------------------------------------------------------------------------- */
 770 
 771 static int
 772 get_args (char *l, char **args, int args_size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 773 {
 774     int argc = 0;
 775 
 776     while (argc < args_size)
 777     {
 778         char *p = l;
 779 
 780         while (*p != '\0' && whiteness (*p))
 781             p++;
 782         if (*p == '\0')
 783             break;
 784         for (l = p + 1; *l != '\0' && !whiteness (*l); l++)
 785             ;
 786         if (*l != '\0')
 787             *l++ = '\0';
 788         args[argc++] = convert (p);
 789     }
 790     args[argc] = (char *) NULL;
 791     return argc;
 792 }
 793 
 794 /* --------------------------------------------------------------------------------------------- */
 795 
 796 static int
 797 this_try_alloc_color_pair (const char *fg, const char *bg, const char *attrs)
     /* [previous][next][first][last][top][bottom][index][help]  */
 798 {
 799     char f[80], b[80], a[80], *p;
 800 
 801     if (bg != NULL && *bg == '\0')
 802         bg = NULL;
 803     if (fg != NULL && *fg == '\0')
 804         fg = NULL;
 805     if (attrs != NULL && *attrs == '\0')
 806         attrs = NULL;
 807 
 808     if ((fg == NULL) && (bg == NULL))
 809         return EDITOR_NORMAL_COLOR;
 810 
 811     if (fg != NULL)
 812     {
 813         g_strlcpy (f, fg, sizeof (f));
 814         p = strchr (f, '/');
 815         if (p != NULL)
 816             *p = '\0';
 817         fg = f;
 818     }
 819     if (bg != NULL)
 820     {
 821         g_strlcpy (b, bg, sizeof (b));
 822         p = strchr (b, '/');
 823         if (p != NULL)
 824             *p = '\0';
 825         bg = b;
 826     }
 827     if ((fg == NULL) || (bg == NULL))
 828     {
 829         /* get colors from skin */
 830         char *editnormal;
 831 
 832         editnormal = mc_skin_get ("editor", "_default_", "default;default");
 833 
 834         if (fg == NULL)
 835         {
 836             g_strlcpy (f, editnormal, sizeof (f));
 837             p = strchr (f, ';');
 838             if (p != NULL)
 839                 *p = '\0';
 840             if (f[0] == '\0')
 841                 g_strlcpy (f, "default", sizeof (f));
 842             fg = f;
 843         }
 844         if (bg == NULL)
 845         {
 846             p = strchr (editnormal, ';');
 847             if ((p != NULL) && (*(++p) != '\0'))
 848                 g_strlcpy (b, p, sizeof (b));
 849             else
 850                 g_strlcpy (b, "default", sizeof (b));
 851             bg = b;
 852         }
 853 
 854         g_free (editnormal);
 855     }
 856 
 857     if (attrs != NULL)
 858     {
 859         g_strlcpy (a, attrs, sizeof (a));
 860         p = strchr (a, '/');
 861         if (p != NULL)
 862             *p = '\0';
 863         /* get_args() mangles the + signs, unmangle 'em */
 864         p = a;
 865         while ((p = strchr (p, SYNTAX_TOKEN_PLUS)) != NULL)
 866             *p++ = '+';
 867         attrs = a;
 868     }
 869     return tty_try_alloc_color_pair (fg, bg, attrs);
 870 }
 871 
 872 /* --------------------------------------------------------------------------------------------- */
 873 
 874 static FILE *
 875 open_include_file (const char *filename)
     /* [previous][next][first][last][top][bottom][index][help]  */
 876 {
 877     FILE *f;
 878 
 879     g_free (error_file_name);
 880     error_file_name = g_strdup (filename);
 881     if (g_path_is_absolute (filename))
 882         return fopen (filename, "r");
 883 
 884     g_free (error_file_name);
 885     error_file_name =
 886         g_build_filename (mc_config_get_data_path (), EDIT_DIR, filename, (char *) NULL);
 887     f = fopen (error_file_name, "r");
 888     if (f != NULL)
 889         return f;
 890 
 891     g_free (error_file_name);
 892     error_file_name = g_build_filename (mc_global.sysconfig_dir, "syntax", filename, (char *) NULL);
 893     f = fopen (error_file_name, "r");
 894     if (f != NULL)
 895         return f;
 896 
 897     g_free (error_file_name);
 898     error_file_name =
 899         g_build_filename (mc_global.share_data_dir, "syntax", filename, (char *) NULL);
 900 
 901     return fopen (error_file_name, "r");
 902 }
 903 
 904 /* --------------------------------------------------------------------------------------------- */
 905 
 906 inline static void
 907 xx_lowerize_line (WEdit * edit, char *line, size_t len)
     /* [previous][next][first][last][top][bottom][index][help]  */
 908 {
 909     if (edit->is_case_insensitive)
 910     {
 911         size_t i;
 912 
 913         for (i = 0; i < len; ++i)
 914             line[i] = tolower (line[i]);
 915     }
 916 }
 917 
 918 /* --------------------------------------------------------------------------------------------- */
 919 /** returns line number on error */
 920 
 921 static int
 922 edit_read_syntax_rules (WEdit * edit, FILE * f, char **args, int args_size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 923 {
 924     FILE *g = NULL;
 925     char *fg, *bg, *attrs;
 926     char last_fg[32] = "", last_bg[32] = "", last_attrs[64] = "";
 927     char whole_right[512];
 928     char whole_left[512];
 929     char *l = NULL;
 930     int save_line = 0, line = 0;
 931     context_rule_t *c = NULL;
 932     gboolean no_words = TRUE;
 933     int result = 0;
 934 
 935     args[0] = NULL;
 936     edit->is_case_insensitive = FALSE;
 937 
 938     strcpy (whole_left, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
 939     strcpy (whole_right, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
 940 
 941     edit->rules = g_ptr_array_new ();
 942 
 943     if (edit->defines == NULL)
 944         edit->defines = g_tree_new ((GCompareFunc) strcmp);
 945 
 946     while (TRUE)
 947     {
 948         char **a;
 949         size_t len;
 950         int argc;
 951 
 952         line++;
 953         l = NULL;
 954 
 955         len = read_one_line (&l, f);
 956         if (len != 0)
 957             xx_lowerize_line (edit, l, len);
 958         else
 959         {
 960             if (g == NULL)
 961                 break;
 962 
 963             fclose (f);
 964             f = g;
 965             g = NULL;
 966             line = save_line + 1;
 967             MC_PTR_FREE (error_file_name);
 968             MC_PTR_FREE (l);
 969             len = read_one_line (&l, f);
 970             if (len == 0)
 971                 break;
 972             xx_lowerize_line (edit, l, len);
 973         }
 974 
 975         argc = get_args (l, args, args_size);
 976         a = args + 1;
 977         if (args[0] == NULL)
 978         {
 979             /* do nothing */
 980         }
 981         else if (strcmp (args[0], "include") == 0)
 982         {
 983             if (g != NULL || argc != 2)
 984             {
 985                 result = line;
 986                 break;
 987             }
 988             g = f;
 989             f = open_include_file (args[1]);
 990             if (f == NULL)
 991             {
 992                 MC_PTR_FREE (error_file_name);
 993                 result = line;
 994                 break;
 995             }
 996             save_line = line;
 997             line = 0;
 998         }
 999         else if (strcmp (args[0], "caseinsensitive") == 0)
1000         {
1001             edit->is_case_insensitive = TRUE;
1002         }
1003         else if (strcmp (args[0], "wholechars") == 0)
1004         {
1005             check_a;
1006             if (strcmp (*a, "left") == 0)
1007             {
1008                 a++;
1009                 g_strlcpy (whole_left, *a, sizeof (whole_left));
1010             }
1011             else if (strcmp (*a, "right") == 0)
1012             {
1013                 a++;
1014                 g_strlcpy (whole_right, *a, sizeof (whole_right));
1015             }
1016             else
1017             {
1018                 g_strlcpy (whole_left, *a, sizeof (whole_left));
1019                 g_strlcpy (whole_right, *a, sizeof (whole_right));
1020             }
1021             a++;
1022             check_not_a;
1023         }
1024         else if (strcmp (args[0], "context") == 0)
1025         {
1026             syntax_keyword_t *k;
1027 
1028             check_a;
1029             if (edit->rules->len == 0)
1030             {
1031                 /* first context is the default */
1032                 if (strcmp (*a, "default") != 0)
1033                     break_a;
1034 
1035                 a++;
1036                 c = g_new0 (context_rule_t, 1);
1037                 g_ptr_array_add (edit->rules, c);
1038                 c->left = g_strdup (" ");
1039                 c->right = g_strdup (" ");
1040             }
1041             else
1042             {
1043                 /* Start new context.  */
1044                 c = g_new0 (context_rule_t, 1);
1045                 g_ptr_array_add (edit->rules, c);
1046                 if (strcmp (*a, "exclusive") == 0)
1047                 {
1048                     a++;
1049                     c->between_delimiters = TRUE;
1050                 }
1051                 check_a;
1052                 if (strcmp (*a, "whole") == 0)
1053                 {
1054                     a++;
1055                     c->whole_word_chars_left = g_strdup (whole_left);
1056                     c->whole_word_chars_right = g_strdup (whole_right);
1057                 }
1058                 else if (strcmp (*a, "wholeleft") == 0)
1059                 {
1060                     a++;
1061                     c->whole_word_chars_left = g_strdup (whole_left);
1062                 }
1063                 else if (strcmp (*a, "wholeright") == 0)
1064                 {
1065                     a++;
1066                     c->whole_word_chars_right = g_strdup (whole_right);
1067                 }
1068                 check_a;
1069                 if (strcmp (*a, "linestart") == 0)
1070                 {
1071                     a++;
1072                     c->line_start_left = TRUE;
1073                 }
1074                 check_a;
1075                 c->left = g_strdup (*a++);
1076                 check_a;
1077                 if (strcmp (*a, "linestart") == 0)
1078                 {
1079                     a++;
1080                     c->line_start_right = TRUE;
1081                 }
1082                 check_a;
1083                 c->right = g_strdup (*a++);
1084                 c->first_left = *c->left;
1085                 c->first_right = *c->right;
1086             }
1087             c->keyword = g_ptr_array_new ();
1088             k = g_new0 (syntax_keyword_t, 1);
1089             g_ptr_array_add (c->keyword, k);
1090             no_words = FALSE;
1091             subst_defines (edit->defines, a, &args[ARGS_LEN]);
1092             fg = *a;
1093             if (*a != NULL)
1094                 a++;
1095             bg = *a;
1096             if (*a != NULL)
1097                 a++;
1098             attrs = *a;
1099             if (*a != NULL)
1100                 a++;
1101             g_strlcpy (last_fg, fg != NULL ? fg : "", sizeof (last_fg));
1102             g_strlcpy (last_bg, bg != NULL ? bg : "", sizeof (last_bg));
1103             g_strlcpy (last_attrs, attrs != NULL ? attrs : "", sizeof (last_attrs));
1104             k->color = this_try_alloc_color_pair (fg, bg, attrs);
1105             k->keyword = g_strdup (" ");
1106             check_not_a;
1107         }
1108         else if (strcmp (args[0], "spellcheck") == 0)
1109         {
1110             if (c == NULL)
1111             {
1112                 result = line;
1113                 break;
1114             }
1115             c->spelling = TRUE;
1116         }
1117         else if (strcmp (args[0], "keyword") == 0)
1118         {
1119             context_rule_t *last_rule;
1120             syntax_keyword_t *k;
1121 
1122             if (no_words)
1123                 break_a;
1124             check_a;
1125             last_rule = CONTEXT_RULE (g_ptr_array_index (edit->rules, edit->rules->len - 1));
1126             k = g_new0 (syntax_keyword_t, 1);
1127             g_ptr_array_add (last_rule->keyword, k);
1128             if (strcmp (*a, "whole") == 0)
1129             {
1130                 a++;
1131                 k->whole_word_chars_left = g_strdup (whole_left);
1132                 k->whole_word_chars_right = g_strdup (whole_right);
1133             }
1134             else if (strcmp (*a, "wholeleft") == 0)
1135             {
1136                 a++;
1137                 k->whole_word_chars_left = g_strdup (whole_left);
1138             }
1139             else if (strcmp (*a, "wholeright") == 0)
1140             {
1141                 a++;
1142                 k->whole_word_chars_right = g_strdup (whole_right);
1143             }
1144             check_a;
1145             if (strcmp (*a, "linestart") == 0)
1146             {
1147                 a++;
1148                 k->line_start = TRUE;
1149             }
1150             check_a;
1151             if (strcmp (*a, "whole") == 0)
1152                 break_a;
1153 
1154             k->keyword = g_strdup (*a++);
1155             subst_defines (edit->defines, a, &args[ARGS_LEN]);
1156             fg = *a;
1157             if (*a != NULL)
1158                 a++;
1159             bg = *a;
1160             if (*a != NULL)
1161                 a++;
1162             attrs = *a;
1163             if (*a != NULL)
1164                 a++;
1165             if (fg == NULL)
1166                 fg = last_fg;
1167             if (bg == NULL)
1168                 bg = last_bg;
1169             if (attrs == NULL)
1170                 attrs = last_attrs;
1171             k->color = this_try_alloc_color_pair (fg, bg, attrs);
1172             check_not_a;
1173         }
1174         else if (*(args[0]) == '#')
1175         {
1176             /* do nothing for comment */
1177         }
1178         else if (strcmp (args[0], "file") == 0)
1179         {
1180             break;
1181         }
1182         else if (strcmp (args[0], "define") == 0)
1183         {
1184             char *key = *a++;
1185             char **argv;
1186 
1187             if (argc < 3)
1188                 break_a;
1189             argv = g_tree_lookup (edit->defines, key);
1190             if (argv != NULL)
1191                 mc_defines_destroy (NULL, argv, NULL);
1192             else
1193                 key = g_strdup (key);
1194 
1195             argv = g_new (char *, argc - 1);
1196             g_tree_insert (edit->defines, key, argv);
1197             while (*a != NULL)
1198                 *argv++ = g_strdup (*a++);
1199             *argv = NULL;
1200         }
1201         else
1202         {
1203             /* anything else is an error */
1204             break_a;
1205         }
1206         MC_PTR_FREE (l);
1207     }
1208     MC_PTR_FREE (l);
1209 
1210     if (edit->rules->len == 0)
1211     {
1212         g_ptr_array_free (edit->rules, TRUE);
1213         edit->rules = NULL;
1214     }
1215 
1216     if (result == 0)
1217     {
1218         size_t i;
1219         GString *first_chars;
1220 
1221         if (edit->rules == NULL)
1222             return line;
1223 
1224         first_chars = g_string_sized_new (32);
1225 
1226         /* collect first character of keywords */
1227         for (i = 0; i < edit->rules->len; i++)
1228         {
1229             size_t j;
1230 
1231             g_string_set_size (first_chars, 0);
1232             c = CONTEXT_RULE (g_ptr_array_index (edit->rules, i));
1233 
1234             g_string_append_c (first_chars, (char) 1);
1235             for (j = 1; j < c->keyword->len; j++)
1236             {
1237                 syntax_keyword_t *k;
1238 
1239                 k = SYNTAX_KEYWORD (g_ptr_array_index (c->keyword, j));
1240                 g_string_append_c (first_chars, k->keyword[0]);
1241             }
1242 
1243             c->keyword_first_chars = g_strndup (first_chars->str, first_chars->len);
1244         }
1245 
1246         g_string_free (first_chars, TRUE);
1247     }
1248 
1249     return result;
1250 }
1251 
1252 /* --------------------------------------------------------------------------------------------- */
1253 
1254 /* returns -1 on file error, line number on error in file syntax */
1255 static int
1256 edit_read_syntax_file (WEdit * edit, GPtrArray * pnames, const char *syntax_file,
     /* [previous][next][first][last][top][bottom][index][help]  */
1257                        const char *editor_file, const char *first_line, const char *type)
1258 {
1259     FILE *f, *g = NULL;
1260     char *args[ARGS_LEN], *l = NULL;
1261     long line = 0;
1262     int result = 0;
1263     char *lib_file;
1264     gboolean found = FALSE;
1265 
1266     f = fopen (syntax_file, "r");
1267     if (f == NULL)
1268     {
1269         lib_file = g_build_filename (mc_global.share_data_dir, "syntax", "Syntax", (char *) NULL);
1270         f = fopen (lib_file, "r");
1271         g_free (lib_file);
1272         if (f == NULL)
1273             return -1;
1274     }
1275 
1276     args[0] = NULL;
1277     while (TRUE)
1278     {
1279         line++;
1280         MC_PTR_FREE (l);
1281         if (read_one_line (&l, f) == 0)
1282             break;
1283         (void) get_args (l, args, ARGS_LEN - 1);        /* Final NULL */
1284         if (args[0] == NULL)
1285             continue;
1286 
1287         /* Looking for 'include ...' lines before first 'file ...' ones */
1288         if (!found && strcmp (args[0], "include") == 0)
1289         {
1290             if (g != NULL)
1291                 continue;
1292 
1293             if (args[1] == NULL || (g = open_include_file (args[1])) == NULL)
1294             {
1295                 result = line;
1296                 break;
1297             }
1298             goto found_type;
1299         }
1300 
1301         /* looking for 'file ...' lines only */
1302         if (strcmp (args[0], "file") != 0)
1303             continue;
1304 
1305         found = TRUE;
1306 
1307         /* must have two args or report error */
1308         if (args[1] == NULL || args[2] == NULL)
1309         {
1310             result = line;
1311             break;
1312         }
1313 
1314         if (pnames != NULL)
1315         {
1316             /* 1: just collecting a list of names of rule sets */
1317             g_ptr_array_add (pnames, g_strdup (args[2]));
1318         }
1319         else if (type != NULL)
1320         {
1321             /* 2: rule set was explicitly specified by the caller */
1322             if (strcmp (type, args[2]) == 0)
1323                 goto found_type;
1324         }
1325         else if (editor_file != NULL && edit != NULL)
1326         {
1327             /* 3: auto-detect rule set from regular expressions */
1328             gboolean q;
1329 
1330             q = mc_search (args[1], DEFAULT_CHARSET, editor_file, MC_SEARCH_T_REGEX);
1331             /* does filename match arg 1 ? */
1332             if (!q && args[3] != NULL)
1333             {
1334                 /* does first line match arg 3 ? */
1335                 q = mc_search (args[3], DEFAULT_CHARSET, first_line, MC_SEARCH_T_REGEX);
1336             }
1337             if (q)
1338             {
1339                 int line_error;
1340                 char *syntax_type;
1341 
1342               found_type:
1343                 syntax_type = args[2];
1344                 line_error = edit_read_syntax_rules (edit, g ? g : f, args, ARGS_LEN - 1);
1345                 if (line_error != 0)
1346                 {
1347                     if (error_file_name == NULL)        /* an included file */
1348                         result = line + line_error;
1349                     else
1350                         result = line_error;
1351                 }
1352                 else
1353                 {
1354                     g_free (edit->syntax_type);
1355                     edit->syntax_type = g_strdup (syntax_type);
1356                     /* if there are no rules then turn off syntax highlighting for speed */
1357                     if (g == NULL && edit->rules->len == 1)
1358                     {
1359                         context_rule_t *r0;
1360 
1361                         r0 = CONTEXT_RULE (g_ptr_array_index (edit->rules, 0));
1362                         if (r0->keyword->len == 1 && !r0->spelling)
1363                         {
1364                             edit_free_syntax_rules (edit);
1365                             break;
1366                         }
1367                     }
1368                 }
1369 
1370                 if (g == NULL)
1371                     break;
1372 
1373                 fclose (g);
1374                 g = NULL;
1375             }
1376         }
1377     }
1378     g_free (l);
1379     fclose (f);
1380     return result;
1381 }
1382 
1383 /* --------------------------------------------------------------------------------------------- */
1384 
1385 static const char *
1386 get_first_editor_line (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1387 {
1388     static char s[256];
1389 
1390     s[0] = '\0';
1391 
1392     if (edit != NULL)
1393     {
1394         size_t i;
1395 
1396         for (i = 0; i < sizeof (s) - 1; i++)
1397         {
1398             s[i] = edit_buffer_get_byte (&edit->buffer, i);
1399             if (s[i] == '\n')
1400             {
1401                 s[i] = '\0';
1402                 break;
1403             }
1404         }
1405 
1406         s[sizeof (s) - 1] = '\0';
1407     }
1408 
1409     return s;
1410 }
1411 
1412 /* --------------------------------------------------------------------------------------------- */
1413 /*** public functions ****************************************************************************/
1414 /* --------------------------------------------------------------------------------------------- */
1415 
1416 int
1417 edit_get_syntax_color (WEdit * edit, off_t byte_index)
     /* [previous][next][first][last][top][bottom][index][help]  */
1418 {
1419     if (!tty_use_colors ())
1420         return 0;
1421 
1422     if (edit->rules != NULL && byte_index < edit->buffer.size && option_syntax_highlighting)
1423     {
1424         edit_get_rule (edit, byte_index);
1425         return translate_rule_to_color (edit, &edit->rule);
1426     }
1427 
1428     return EDITOR_NORMAL_COLOR;
1429 }
1430 
1431 /* --------------------------------------------------------------------------------------------- */
1432 
1433 void
1434 edit_free_syntax_rules (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1435 {
1436     if (edit == NULL)
1437         return;
1438 
1439     if (edit->defines != NULL)
1440         destroy_defines (&edit->defines);
1441 
1442     if (edit->rules == NULL)
1443         return;
1444 
1445     edit_get_rule (edit, -1);
1446     MC_PTR_FREE (edit->syntax_type);
1447 
1448     g_ptr_array_foreach (edit->rules, (GFunc) context_rule_free, NULL);
1449     g_ptr_array_free (edit->rules, TRUE);
1450     edit->rules = NULL;
1451     g_slist_free_full (edit->syntax_marker, g_free);
1452     edit->syntax_marker = NULL;
1453     tty_color_free_all_tmp ();
1454 }
1455 
1456 /* --------------------------------------------------------------------------------------------- */
1457 /**
1458  * Load rules into edit struct.  Either edit or *pnames must be NULL.  If
1459  * edit is NULL, a list of types will be stored into names.  If type is
1460  * NULL, then the type will be selected according to the filename.
1461  * type must be edit->syntax_type or NULL
1462  */
1463 void
1464 edit_load_syntax (WEdit * edit, GPtrArray * pnames, const char *type)
     /* [previous][next][first][last][top][bottom][index][help]  */
1465 {
1466     int r;
1467     char *f = NULL;
1468 
1469     if (option_auto_syntax)
1470         type = NULL;
1471 
1472     if (edit != NULL)
1473     {
1474         char *saved_type;
1475 
1476         saved_type = g_strdup (type);   /* save edit->syntax_type */
1477         edit_free_syntax_rules (edit);
1478         edit->syntax_type = saved_type; /* restore edit->syntax_type */
1479     }
1480 
1481     if (!tty_use_colors ())
1482         return;
1483 
1484     if (!option_syntax_highlighting && (pnames == NULL || pnames->len == 0))
1485         return;
1486 
1487     if (edit != NULL && edit->filename_vpath == NULL)
1488         return;
1489 
1490     f = mc_config_get_full_path (EDIT_SYNTAX_FILE);
1491     if (edit != NULL)
1492         r = edit_read_syntax_file (edit, pnames, f, vfs_path_as_str (edit->filename_vpath),
1493                                    get_first_editor_line (edit),
1494                                    option_auto_syntax ? NULL : edit->syntax_type);
1495     else
1496         r = edit_read_syntax_file (NULL, pnames, f, NULL, "", NULL);
1497     if (r == -1)
1498     {
1499         edit_free_syntax_rules (edit);
1500         message (D_ERROR, _("Load syntax file"),
1501                  _("Cannot open file %s\n%s"), f, unix_error_string (errno));
1502     }
1503     else if (r != 0)
1504     {
1505         edit_free_syntax_rules (edit);
1506         message (D_ERROR, _("Load syntax file"),
1507                  _("Error in file %s on line %d"), error_file_name != NULL ? error_file_name : f,
1508                  r);
1509         MC_PTR_FREE (error_file_name);
1510     }
1511 
1512     g_free (f);
1513 }
1514 
1515 /* --------------------------------------------------------------------------------------------- */
1516 
1517 const char *
1518 edit_get_syntax_type (const WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1519 {
1520     return edit->syntax_type;
1521 }
1522 
1523 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */