syntax.c
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:166k
源码类别:

编辑器/阅读器

开发平台:

DOS

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  */
  8. /*
  9.  * syntax.c: code for syntax highlighting
  10.  */
  11. #include "vim.h"
  12. /*
  13.  * Structure that stores information about a highlight group.
  14.  * The ID of a highlight group is also called group ID.  It is the index in
  15.  * the highlight_ga array PLUS ONE.
  16.  */
  17. struct hl_group
  18. {
  19.     char_u *sg_name; /* highlight group name */
  20.     char_u *sg_name_u; /* uppercase of sg_name */
  21. /* for normal terminals */
  22.     int sg_term; /* "term=" highlighting attributes */
  23.     char_u *sg_start; /* terminal string for start highl */
  24.     char_u *sg_stop; /* terminal string for stop highl */
  25.     int sg_term_attr; /* NextScreen attr for term mode */
  26. /* for color terminals */
  27.     int sg_cterm; /* "cterm=" highlighting attr */
  28.     int sg_cterm_bold; /* bold attr was set for light color */
  29.     int sg_cterm_fg; /* terminal fg color number + 1 */
  30.     int sg_cterm_bg; /* terminal bg color number + 1 */
  31.     int sg_cterm_attr; /* NextScreen attr for color term mode */
  32. #ifdef USE_GUI
  33. /* for when using the GUI */
  34.     int sg_gui; /* "gui=" highlighting attributes */
  35.     GuiColor sg_gui_fg; /* GUI foreground color handle + 1 */
  36.     char_u *sg_gui_fg_name;/* GUI foreground color name */
  37.     GuiColor sg_gui_bg; /* GUI background color handle + 1 */
  38.     char_u *sg_gui_bg_name;/* GUI background color name */
  39.     GuiFont sg_font; /* GUI font handle */
  40.     char_u *sg_font_name;  /* GUI font name */
  41.     int sg_gui_attr;    /* NextScreen attr for GUI mode */
  42. #endif
  43.     int sg_link; /* link to this highlight group ID */
  44.     int sg_set; /* combination of SG_* */
  45. };
  46. #define SG_TERM 1 /* term has been set */
  47. #define SG_CTERM 2 /* cterm has been set */
  48. #define SG_GUI 4 /* gui has been set */
  49. #define SG_LINK 8 /* link has been set */
  50. static struct growarray highlight_ga;     /* highlight groups for
  51.        'highlight' option */
  52. #define HL_TABLE() ((struct hl_group *)((highlight_ga.ga_data)))
  53. static int include_link = FALSE; /* include "link" for expansion */
  54. /*
  55.  * The "term", "cterm" and "gui" arguments can be any combination of the
  56.  * following names, separated by commas (but no spaces!).
  57.  */
  58. static char *(hl_name_table[]) =
  59.     {"bold", "standout", "underline", "italic", "reverse", "inverse", "NONE"};
  60. static int hl_attr_table[] =
  61.     {HL_BOLD, HL_STANDOUT, HL_UNDERLINE, HL_ITALIC, HL_INVERSE, HL_INVERSE, 0};
  62. static int get_attr_entry  __ARGS((struct growarray *table, struct attr_entry *aep));
  63. static int syn_namen2id __ARGS((char_u *linep, int len));
  64. static void syn_unadd_group __ARGS((void));
  65. static void set_hl_attr __ARGS((int idx));
  66. static void highlight_list_one __ARGS((int id));
  67. static void highlight_list_two __ARGS((int cnt, int attr));
  68. static int highlight_list_arg __ARGS((int id, int didh, int type, int iarg, char_u *sarg, char *name));
  69. static int syn_add_group __ARGS((char_u *name));
  70. static int syn_list_header __ARGS((int did_header, int outlen, int id));
  71. static void highlight_list __ARGS((void));
  72. static void highlight_clear __ARGS((int idx));
  73. #ifdef USE_GUI
  74. static void gui_do_one_color __ARGS((int idx));
  75. static int  set_group_colors __ARGS((char_u *name, GuiColor *fgp, GuiColor *bgp));
  76. static GuiColor color_name2handle __ARGS((char_u *name));
  77. static GuiFont font_name2handle __ARGS((char_u *name));
  78. #endif
  79. /*
  80.  * An attribute number is the index in attr_table plus ATTR_OFF.
  81.  */
  82. #define ATTR_OFF (HL_ALL + 1)
  83. #ifdef SYNTAX_HL
  84. #define SYN_NAMELEN 50 /* maximum length of a syntax name */
  85. /* different types of offsets that are possible */
  86. #define SPO_MS_OFF 0 /* match  start offset */
  87. #define SPO_ME_OFF 1 /* match  end offset */
  88. #define SPO_HS_OFF 2 /* highl. start offset */
  89. #define SPO_HE_OFF 3 /* highl. end offset */
  90. #define SPO_RS_OFF 4 /* region start offset */
  91. #define SPO_RE_OFF 5 /* region end offset */
  92. #define SPO_LC_OFF 6 /* leading context offset */
  93. #define SPO_COUNT 7
  94. static char *(spo_name_tab[SPO_COUNT]) =
  95.     {"ms=", "me=", "hs=", "he=", "rs=", "re=", "lc="};
  96. /*
  97.  * The patterns that are being searched for are stored in a syn_pattern.
  98.  * A match item consists of one pattern.
  99.  * A start/end item consists of n start patterns and m end patterns.
  100.  * A start/skip/end item consists of n start patterns, one skip pattern and m
  101.  * end patterns.
  102.  * For the latter two, the patterns are always consecutive: start-skip-end.
  103.  *
  104.  * A character offset can be given for the matched text (_m_start and _m_end)
  105.  * and for the actually highlighted text (_h_start and _h_end).
  106.  */
  107. struct syn_pattern
  108. {
  109.     char  sp_type;     /* see SPTYPE_ defines below */
  110.     char  sp_syncing;     /* this item used for syncing */
  111.     short  sp_flags;     /* see HL_ defines below */
  112.     int  sp_syn_inc_lvl;    /* ":syn include" level of item */
  113.     short  sp_syn_id;     /* highlight group ID of item */
  114.     short  sp_syn_match_id;   /* highlight group ID of pattern */
  115.     char_u *sp_pattern;     /* regexp to match, pattern */
  116.     vim_regexp *sp_prog;     /* regexp to match, program */
  117.     int  sp_ic;     /* ignore-case flag for sp_prog */
  118.     short  sp_off_flags;     /* see below */
  119.     int  sp_offsets[SPO_COUNT]; /* offsets */
  120.     short *sp_cont_list;     /* cont. group IDs, if non-zero */
  121.     short *sp_next_list;     /* next group IDs, if non-zero */
  122.     int  sp_sync_idx;     /* sync item index (syncing only) */
  123.     int  sp_line_id;     /* ID of last line where tried */
  124.     int  sp_startcol;     /* next match in sp_line_id line */
  125. };
  126. /* The sp_off_flags are computed like this:
  127.  * offset from the start of the matched text: (1 << SPO_XX_OFF)
  128.  * offset from the end  of the matched text: (1 << (SPO_XX_OFF + SPO_COUNT))
  129.  * When both are present, only one is used.
  130.  */
  131. #define SPTYPE_MATCH 1 /* match keyword with this group ID */
  132. #define SPTYPE_START 2 /* match a regexp, start of item */
  133. #define SPTYPE_END 3 /* match a regexp, end of item */
  134. #define SPTYPE_SKIP 4 /* match a regexp, skip within item */
  135. #define HL_CONTAINED 0x01 /* not used on toplevel */
  136. #define HL_TRANSP 0x02 /* has no highlighting */
  137. #define HL_ONELINE 0x04 /* match within one line only */
  138. #define HL_HAS_EOL 0x08 /* end pattern that matches with $ */
  139. #define HL_SYNC_HERE 0x10 /* sync point after this item (syncing only) */
  140. #define HL_SYNC_THERE 0x20 /* sync point at current line (syncing only) */
  141. #define HL_MATCH 0x40 /* use match ID instead of item ID */
  142. #define HL_SKIPNL 0x80 /* nextgroup can skip newlines */
  143. #define HL_SKIPWHITE 0x100 /* nextgroup can skip white space */
  144. #define HL_SKIPEMPTY 0x200 /* nextgroup can skip empty lines */
  145. #define HL_KEEPEND 0x400 /* end match always kept */
  146. #define SYN_ITEMS(buf) ((struct syn_pattern *)((buf)->b_syn_patterns.ga_data))
  147. #define NONE_IDX -2 /* value of sp_sync_idx for "NONE" */
  148. /*
  149.  * Flags for b_syn_sync_flags:
  150.  */
  151. #define SF_CCOMMENT 0x01 /* sync on a C-style comment */
  152. #define SF_MATCH 0x02 /* sync by matching a pattern */
  153. /*
  154.  * Struct used to store states for the start of some lines for a buffer.
  155.  */
  156. struct buf_state
  157. {
  158.     int     bs_idx; /* index of pattern */
  159.     int     bs_flags; /* flags for pattern */
  160. };
  161. #define SYN_STATE_P(ssp)    ((struct buf_state *)((ssp)->ga_data))
  162. /*
  163.  * Settings for keyword hash table.  It uses a simplistic hash function: add
  164.  * all characters together, modulo KHASH_SIZE.
  165.  */
  166. #define KHASH_SIZE 512
  167. #define KHASH_MASK (KHASH_SIZE - 1)
  168. #define MAXKEYWLEN 80     /* maximum length of a keyword */
  169. /*
  170.  * The attributes of the syntax item that has been recognized.
  171.  */
  172. static int current_attr = 0;     /* attr of current syntax word */
  173. static int current_id = 0;     /* ID of current char for syn_get_id() */
  174. static int current_trans_id = 0;    /* idem, transparancy removed */
  175. struct syn_cluster
  176. {
  177.     char_u     *scl_name;     /* syntax cluster name */
  178.     char_u     *scl_name_u;    /* uppercase of scl_name */
  179.     short     *scl_list;     /* IDs in this syntax cluster */
  180. };
  181. /*
  182.  * Syntax group IDs greater than or equal to this are actually cluster IDs.  I
  183.  * was gonna use SHRT_MAX/2, but apparently not everyone has <limits.h>...
  184.  */
  185. #define CLUSTER_ID_MIN 15000
  186. /*
  187.  * Methods of combining two clusters
  188.  */
  189. #define CLUSTER_REPLACE     1 /* replace first list with second */
  190. #define CLUSTER_ADD     2 /* add second list to first */
  191. #define CLUSTER_SUBTRACT    3 /* subtract second list from first */
  192. #define SYN_CLSTR(buf) ((struct syn_cluster *)((buf)->b_syn_clusters.ga_data))
  193. /*
  194.  * Annoying Hack(TM):  ":syn include" needs this pointer to pass to
  195.  * expand_filename().  Most of the other syntax commands don't need it, so
  196.  * instead of passing it to them, we stow it here.
  197.  */
  198. static char_u **syn_cmdlinep;
  199. /*
  200.  * Another Annoying Hack(TM):  To prevent rules from higher or lower in the
  201.  * ":syn include" stack from from leaking into ALLBUT lists, we track the
  202.  * current stack "level".
  203.  */
  204. static int current_syn_inc_lvl = 0;
  205. /*
  206.  * To reduce the time spent in keepend(), remember at which level in the state
  207.  * stack the first item with "keepend" is present.  When "-1", there is no
  208.  * "keepend" on the stack.
  209.  */
  210. static int keepend_level = -1;
  211. /*
  212.  * For the current state we need to remember more than just the idx.
  213.  * When si_m_endcol is 0, the items other than si_idx are unknown.
  214.  */
  215. struct state_item
  216. {
  217.     int     si_idx;     /* index of syntax pattern */
  218.     int     si_id;     /* highlight group ID for keywords */
  219.     int     si_trans_id;     /* idem, transparancy removed */
  220.     int     si_m_lnum;     /* lnum of the match */
  221.     int     si_m_startcol;     /* starting column of the match */
  222.     int     si_m_endcol;     /* ending column of the match */
  223.     int     si_h_startcol;     /* starting column of the highlighting */
  224.     int     si_h_endcol;     /* ending column of the highlighting */
  225.     int     si_eoe_col;     /* ending column of end pattern */
  226.     int     si_end_idx;     /* group ID for end pattern or zero */
  227.     int     si_ends;     /* if match ends after si_m_endcol */
  228.     int     si_attr;     /* attributes in this state */
  229.     int     si_flags;     /* HL_HAS_EOL flag in this state, and
  230.        HL_SKIP* for si_next_list */
  231.     short   *si_cont_list;     /* list of contained groups */
  232.     short   *si_next_list;     /* nextgroup IDs after this item ends */
  233. };
  234. #define KEYWORD_IDX -1     /* value of si_idx for keywords */
  235. #define CONTAINS_ALLBUT 9999     /* value of id for contains ALLBUT */
  236. #define ID_LIST_ALL (short *)-1 /* valid of si_cont_list for containing all
  237.        but contained groups */
  238. /*
  239.  * The next possible match for any pattern is remembered, to avoid having to
  240.  * try for a match in each column.
  241.  * If next_match_idx == -1, not tried (in this line) yet.
  242.  * If next_match_col == MAXCOL, no match found in this line.
  243.  */
  244. static int next_match_col;     /* column for start of next match */
  245. static int next_match_m_endcol;     /* column for end of next match */
  246. static int next_match_h_startcol;   /* column for highl. start of next match */
  247. static int next_match_h_endcol;     /* column for highl. end of next match */
  248. static int next_match_idx;     /* index of matched item */
  249. static int next_match_flags;     /* flags for next match */
  250. static int next_match_eos_col;     /* column for end of start pattern */
  251. static int next_match_eoe_col;     /* column for end of end pattern */
  252. static int next_match_end_idx;     /* ID of group for end pattern or zero */
  253. /*
  254.  * A state stack is an array of integers or struct state_item, stored in a
  255.  * struct growarray.  A state stack is invalid if it's itemsize entry is zero.
  256.  */
  257. #define INVALID_STATE(ssp)  ((ssp)->ga_itemsize == 0)
  258. #define VALID_STATE(ssp)    ((ssp)->ga_itemsize != 0)
  259. /*
  260.  * The current state (within the line) of the recognition engine.
  261.  */
  262. static BUF *syn_buf; /* current buffer for highlighting */
  263. static linenr_t current_lnum = 0; /* lnum of current state */
  264. static int current_state_stored = 0; /* TRUE if stored current state
  265.    * after setting current_finished */
  266. static colnr_t current_col = 0; /* column of current state */
  267. static int current_finished = 0; /* current line has been finished */
  268. static struct growarray current_state /* current stack of state_items */
  269. = {0, 0, 0, 0, NULL};
  270. static short *current_next_list = NULL; /* when non-zero, nextgroup list */
  271. static int current_next_flags = 0; /* flags for current_next_list */
  272. static int current_line_id = 0; /* unique number for current line */
  273. #define CUR_STATE(idx) ((struct state_item *)(current_state.ga_data))[idx]
  274. static void syn_sync __ARGS((WIN *wp, linenr_t lnum));
  275. static int syn_match_linecont __ARGS((linenr_t lnum));
  276. static void syn_start_line __ARGS((void));
  277. static void syn_free_all_states __ARGS((BUF *buf));
  278. static void syn_clear_states __ARGS((int start, int end));
  279. static void store_current_state __ARGS((void));
  280. static void invalidate_current_state __ARGS((void));
  281. static void validate_current_state __ARGS((void));
  282. static void copy_state_to_current __ARGS((struct syn_state *from));
  283. static void move_state __ARGS((int from, int to));
  284. static int syn_finish_line __ARGS((int syncing));
  285. static int syn_current_attr __ARGS((int syncing, char_u *line));
  286. static int did_match_already __ARGS((int idx));
  287. static struct state_item *push_next_match __ARGS((struct state_item *cur_si, char_u *line));
  288. static void check_state_ends __ARGS((char_u *line));
  289. static void update_si_attr __ARGS((int idx));
  290. static void check_keepend __ARGS((void));
  291. static void update_si_end __ARGS((struct state_item *sip, char_u *line, int startcol));
  292. static short *copy_id_list __ARGS((short *list));
  293. static int in_id_list __ARGS((short *cont_list, int id, int inclvl, int contained));
  294. static int syn_regexec __ARGS((vim_regexp *prog, char_u *string, int at_bol));
  295. static int push_current __ARGS((int idx));
  296. static void pop_current __ARGS((void));
  297. static char_u *find_endp __ARGS((int idx, char_u *sstart, int at_bol, char_u **hl_endp, int *flagsp, char_u **end_endp, int *end_idx));
  298. static char_u *syn_add_end_off __ARGS((struct syn_pattern *spp, int idx, int extra));
  299. static char_u *syn_add_start_off __ARGS((struct syn_pattern *spp, int idx, int extra));
  300. static int check_keyword_id __ARGS((char_u *line, int startcol, int *endcol, int *flags, short **next_list, struct state_item *cur_si));
  301. static void syn_cmd_case __ARGS((EXARG *eap, int syncing));
  302. static void syntax_sync_clear __ARGS((void));
  303. static void syn_remove_pattern __ARGS((BUF *buf, int idx));
  304. static void syn_clear_pattern __ARGS((BUF *buf, int i));
  305. static void syn_clear_cluster __ARGS((BUF *buf, int i));
  306. static void syn_cmd_clear __ARGS((EXARG *eap, int syncing));
  307. static void syn_clear_one __ARGS((int id, int syncing));
  308. static void syn_cmd_on __ARGS((EXARG *eap, int syncing));
  309. static void syn_cmd_off __ARGS((EXARG *eap, int syncing));
  310. static void syn_cmd_list __ARGS((EXARG *eap, int syncing));
  311. static void syn_lines_msg __ARGS((void));
  312. static void syn_list_one __ARGS((int id, int syncing, int link_only));
  313. static void syn_list_cluster __ARGS((int id));
  314. static void put_id_list __ARGS((char_u *name, short *list, int attr));
  315. static void put_pattern __ARGS((char *s, int c, struct syn_pattern *spp, int attr));
  316. static int syn_list_keywords __ARGS((int id, struct keyentry **ktabp, int did_header, int attr));
  317. static void syn_clear_keyword __ARGS((int id, struct keyentry **ktabp));
  318. static void free_keywtab __ARGS((struct keyentry **ktabp));
  319. static void add_keyword __ARGS((char_u *name, int id, int flags, short *next_list));
  320. static char_u *get_group_name __ARGS((char_u *arg, char_u **name_end));
  321. static char_u *get_syn_options __ARGS((char_u *arg, int *flagsp, int *sync_idx,
  322.     short **cont_list, short **next_list));
  323. static void syn_cmd_include __ARGS((EXARG *eap, int syncing));
  324. static void syn_cmd_keyword __ARGS((EXARG *eap, int syncing));
  325. static void syn_cmd_match __ARGS((EXARG *eap, int syncing));
  326. static void syn_cmd_region __ARGS((EXARG *eap, int syncing));
  327. #ifdef __BORLANDC__
  328. static int _RTLENTRYF syn_compare_stub __ARGS((const void *v1, const void *v2));
  329. #else
  330. static int syn_compare_stub __ARGS((const void *v1, const void *v2));
  331. #endif
  332. static void syn_cmd_cluster __ARGS((EXARG *eap, int syncing));
  333. static int syn_scl_name2id __ARGS((char_u *name));
  334. static int syn_scl_namen2id __ARGS((char_u *linep, int len));
  335. static int syn_check_cluster __ARGS((char_u *pp, int len));
  336. static int syn_add_cluster __ARGS((char_u *name));
  337. static void init_syn_patterns __ARGS((void));
  338. static char_u *get_syn_pattern __ARGS((char_u *arg, struct syn_pattern *ci));
  339. static void syn_cmd_sync __ARGS((EXARG *eap, int syncing));
  340. static int get_id_list __ARGS((char_u **arg, int keylen, short **list));
  341. static void syn_combine_list __ARGS((short **clstr1, short **clstr2, int list_op));
  342. static void syn_incl_toplevel __ARGS((int id, int *flagsp));
  343. /*
  344.  * Start the syntax recognition for a line.  This function is normally called
  345.  * from the screen updating, once for each consecutive line.
  346.  * The buffer is remembered in syn_buf, because get_syntax_attr() doesn't get
  347.  * it. Careful: curbuf and curwin are likely to point to another buffer and
  348.  * window.
  349.  */
  350.     void
  351. syntax_start(wp, lnum)
  352.     WIN *wp;
  353.     linenr_t lnum;
  354. {
  355.     long to, from, first;
  356.     long diff;
  357.     int idx;
  358.     reg_syn = TRUE; /* let vim_regexec() know we're using syntax */
  359.     /*
  360.      * After switching buffers, invalidate current_state.
  361.      */
  362.     if (syn_buf != wp->w_buffer)
  363.     {
  364. invalidate_current_state();
  365. syn_buf = wp->w_buffer;
  366.     }
  367.     /*
  368.      * Keep syncing info for ten lines above the window.  This is a compromise
  369.      * between computing extra lines (jumping around) and reducing computions
  370.      * (mostly when scrolling up).
  371.      */
  372. #define SYNC_LINES 10
  373.     /*
  374.      * If the screen height has changed, re-allocate b_syn_states[].
  375.      * Use the screen height plus SYNC_LINES, so some lines above and one
  376.      * line below the window can always be stored too.
  377.      */
  378.     if (syn_buf->b_syn_states_len != Rows + SYNC_LINES)
  379.     {
  380. syn_free_all_states(syn_buf);
  381. syn_buf->b_syn_states = (struct syn_state *)alloc_clear(
  382.   (int)((Rows + SYNC_LINES) * sizeof(struct syn_state)));
  383. if (syn_buf->b_syn_states == NULL)     /* out of memory */
  384. {
  385.     syn_buf->b_syn_states_len = 0;
  386.     goto theend;
  387. }
  388. syn_buf->b_syn_states_len = Rows + SYNC_LINES;
  389. syn_buf->b_syn_states_lnum = 0;
  390. syn_buf->b_syn_change_lnum = MAXLNUM;
  391.     }
  392.     /*
  393.      * Remove items from b_syn_states[] that have changes in or before them.
  394.      */
  395.     if (syn_buf->b_syn_change_lnum != MAXLNUM)
  396.     {
  397. /* if change is before the end of the array, something to clear */
  398. if (syn_buf->b_syn_change_lnum <
  399.    syn_buf->b_syn_states_lnum + syn_buf->b_syn_states_len - 1)
  400. {
  401.     /* line before the start changed: clear all entries */
  402.     if (syn_buf->b_syn_change_lnum < syn_buf->b_syn_states_lnum)
  403. idx = 0;
  404.     else
  405. idx = syn_buf->b_syn_change_lnum -
  406.        syn_buf->b_syn_states_lnum + 1;
  407.     syn_clear_states(idx, syn_buf->b_syn_states_len);
  408. }
  409. if (syn_buf->b_syn_change_lnum <= current_lnum)
  410.     invalidate_current_state();
  411. syn_buf->b_syn_change_lnum = MAXLNUM;
  412.     }
  413.     /*
  414.      * If the topline has changed out of range of b_syn_states[], move the
  415.      * items in the array.
  416.      */
  417.     if (wp->w_topline < syn_buf->b_syn_states_lnum)
  418.     {
  419. /*
  420.  * Topline is above the array: Move entries down.
  421.  * (w_topline - SYNC_LINES) is the new first line in * b_syn_states[].
  422.  */
  423. to = syn_buf->b_syn_states_len - 1;
  424. if (wp->w_topline > SYNC_LINES)
  425.     first = wp->w_topline - SYNC_LINES;
  426. else
  427.     first = 0;
  428. from = to - (syn_buf->b_syn_states_lnum - first);
  429. while (from >= 0)
  430. {
  431.     move_state((int)from, (int)to);
  432.     --from;
  433.     --to;
  434. }
  435. syn_clear_states(0, (int)(to + 1));
  436. syn_buf->b_syn_states_lnum = first;
  437.     }
  438.     else if ((diff = (wp->w_topline + wp->w_height) -
  439.  (syn_buf->b_syn_states_lnum + syn_buf->b_syn_states_len)) > 0)
  440.     {
  441. /*
  442.  * The last line in the window is below the array: Move entries up
  443.  * "diff" positions.
  444.  */
  445. to = 0;
  446. from = to + diff;
  447. while (from < syn_buf->b_syn_states_len)
  448. {
  449.     move_state((int)from, (int)to);
  450.     ++from;
  451.     ++to;
  452. }
  453. syn_clear_states((int)to, syn_buf->b_syn_states_len);
  454. syn_buf->b_syn_states_lnum += diff;
  455.     }
  456.     /*
  457.      * If the state of the end of the previous line is useful, store it.
  458.      */
  459.     if (VALID_STATE(&current_state)
  460.     && current_lnum < lnum
  461.     && current_lnum >= syn_buf->b_syn_states_lnum
  462.     && current_lnum <
  463. syn_buf->b_syn_states_lnum + syn_buf->b_syn_states_len
  464.     && current_lnum < syn_buf->b_ml.ml_line_count)
  465.     {
  466. (void)syn_finish_line(FALSE);
  467. if (!current_state_stored)
  468. {
  469.     ++current_lnum;
  470.     store_current_state();
  471. }
  472. /*
  473.  * If the current_lnum is now the same as "lnum", keep the current
  474.  * state (this happens very often!).  Otherwise invalidate
  475.  * current_state and figure it out below.
  476.  */
  477. if (current_lnum != lnum)
  478.     invalidate_current_state();
  479.     }
  480.     else
  481. invalidate_current_state();
  482.     /*
  483.      * Try to synchronize from a saved state in b_syn_states[].
  484.      * Only do this if lnum is not before and not to far beyond a saved state.
  485.      */
  486.     if (INVALID_STATE(&current_state))
  487.     {
  488. diff = syn_buf->b_syn_sync_minlines;
  489. if (diff < Rows * 2)
  490.     diff = Rows * 2;     /* parse less then two screenfulls extra */
  491. if (lnum >= syn_buf->b_syn_states_lnum &&
  492. lnum <= syn_buf->b_syn_states_lnum +
  493.      syn_buf->b_syn_states_len + diff)
  494. {
  495.     idx = lnum - syn_buf->b_syn_states_lnum;
  496.     if (idx >= syn_buf->b_syn_states_len)
  497. idx = syn_buf->b_syn_states_len - 1;
  498.     for ( ; idx >= 0; --idx)
  499.     {
  500. if (VALID_STATE(&syn_buf->b_syn_states[idx].sst_ga))
  501. {
  502.     current_lnum = syn_buf->b_syn_states_lnum + idx;
  503.     copy_state_to_current(&(syn_buf->b_syn_states[idx]));
  504.     break;
  505. }
  506.     }
  507. }
  508.     }
  509.     /*
  510.      * If "lnum" is before or far beyond a line with a saved state, need to
  511.      * re-synchronize.
  512.      */
  513.     if (INVALID_STATE(&current_state))
  514. syn_sync(wp, lnum);
  515.     /*
  516.      * Advance from the sync point or saved state until the current line.
  517.      */
  518.     while (current_lnum < lnum)
  519.     {
  520. syn_start_line();
  521. (void)syn_finish_line(FALSE);
  522. ++current_lnum;
  523. store_current_state();
  524. /* This can take a long time: break when CTRL-C pressed. */
  525. line_breakcheck();
  526. if (got_int)
  527. {
  528.     current_lnum = lnum;
  529.     break;
  530. }
  531.     }
  532.     syn_start_line();
  533. theend:
  534.     reg_syn = FALSE;
  535. }
  536. /*
  537.  * Try to find a synchronisation point for line "lnum".
  538.  *
  539.  * This sets current_lnum and the current state.  One of three methods is
  540.  * used:
  541.  * 1. Search backwards for the end of a C-comment.
  542.  * 2. Search backwards for given sync patterns.
  543.  * 3. Simply start on a given number of lines above "lnum".
  544.  */
  545.     static void
  546. syn_sync(wp, start_lnum)
  547.     WIN *wp;
  548.     linenr_t start_lnum;
  549. {
  550.     BUF *curbuf_save;
  551.     WIN *curwin_save;
  552.     FPOS cursor_save;
  553.     int idx;
  554.     linenr_t lnum;
  555.     linenr_t end_lnum;
  556.     linenr_t break_lnum;
  557.     int had_sync_point;
  558.     struct state_item *cur_si;
  559.     struct syn_pattern *spp;
  560.     char_u *line;
  561.     int found_flags = 0;
  562.     int found_match_idx = 0;
  563.     linenr_t found_current_lnum = 0;
  564.     int found_current_col= 0;
  565.     colnr_t found_m_endcol = 0;
  566.     /*
  567.      * Clear any current state that might be hanging around.
  568.      */
  569.     invalidate_current_state();
  570.     /*
  571.      * Start at least "minlines" back.
  572.      * Also subtract SYNC_LINES, so that b_syn_states[] is filled with valid
  573.      * states.
  574.      * Default starting point for parsing is there.
  575.      */
  576.     start_lnum -= syn_buf->b_syn_sync_minlines + SYNC_LINES;
  577.     if (start_lnum < 1)
  578. start_lnum = 1;
  579.     current_lnum = start_lnum;
  580.     /*
  581.      * 1. Search backwards for the end of a C-style comment.
  582.      */
  583.     if (syn_buf->b_syn_sync_flags & SF_CCOMMENT)
  584.     {
  585. /* need to make syn_buf the current buffer for a moment */
  586. curwin_save = curwin;
  587. curwin = wp;
  588. curbuf_save = curbuf;
  589. curbuf = syn_buf;
  590. /*
  591.  * Skip lines that end in a backslash.
  592.  */
  593. for ( ; start_lnum > 1; --start_lnum)
  594. {
  595.     line = ml_get(start_lnum - 1);
  596.     if (*line == NUL || *(line + STRLEN(line) - 1) != '\')
  597. break;
  598. }
  599. current_lnum = start_lnum;
  600. /* set cursor to start of search */
  601. cursor_save = wp->w_cursor;
  602. wp->w_cursor.lnum = start_lnum;
  603. wp->w_cursor.col = 0;
  604. /*
  605.  * If the line is inside a comment, need to find the syntax item that
  606.  * defines the comment.
  607.  * Restrict the search for the end of a comment to b_syn_sync_maxlines.
  608.  */
  609. if (find_start_comment((int)syn_buf->b_syn_sync_maxlines) != NULL)
  610. {
  611.     for (idx = syn_buf->b_syn_patterns.ga_len; --idx >= 0; )
  612. if (SYN_ITEMS(syn_buf)[idx].sp_syn_id == syn_buf->b_syn_sync_id
  613. && SYN_ITEMS(syn_buf)[idx].sp_type == SPTYPE_START)
  614. {
  615.     validate_current_state();
  616.     if (push_current(idx) == OK)
  617. update_si_attr(current_state.ga_len - 1);
  618.     break;
  619. }
  620. }
  621. /* restore cursor and buffer */
  622. wp->w_cursor = cursor_save;
  623. curwin = curwin_save;
  624. curbuf = curbuf_save;
  625.     }
  626.     /*
  627.      * 2. Search backwards for given sync patterns.
  628.      */
  629.     else if (syn_buf->b_syn_sync_flags & SF_MATCH)
  630.     {
  631. if (syn_buf->b_syn_sync_maxlines
  632.  && start_lnum > syn_buf->b_syn_sync_maxlines)
  633.     break_lnum = start_lnum - syn_buf->b_syn_sync_maxlines;
  634. else
  635.     break_lnum = 0;
  636. end_lnum = start_lnum;
  637. lnum = start_lnum;
  638. while (--lnum > break_lnum)
  639. {
  640.     /* This can take a long time: break when CTRL-C pressed. */
  641.     line_breakcheck();
  642.     if (got_int)
  643.     {
  644. invalidate_current_state();
  645. current_lnum = start_lnum;
  646. break;
  647.     }
  648.     /*
  649.      * Check if the previous line has the line-continuation pattern.
  650.      */
  651.     if (lnum > 1 && syn_match_linecont(lnum - 1))
  652. continue;
  653.     /*
  654.      * Start with nothing on the state stack
  655.      */
  656.     validate_current_state();
  657.     for (current_lnum = lnum; current_lnum < end_lnum; ++current_lnum)
  658.     {
  659. syn_start_line();
  660. for (;;)
  661. {
  662.     had_sync_point = syn_finish_line(TRUE);
  663.     /*
  664.      * When a sync point has been found, remember where, and
  665.      * continue to look for another one, further on in the line.
  666.      */
  667.     if (had_sync_point && current_state.ga_len)
  668.     {
  669. cur_si = &CUR_STATE(current_state.ga_len - 1);
  670. spp = &(SYN_ITEMS(syn_buf)[cur_si->si_idx]);
  671. found_flags = spp->sp_flags;
  672. found_match_idx = spp->sp_sync_idx;
  673. found_current_lnum = current_lnum;
  674. found_current_col = current_col;
  675. found_m_endcol = cur_si->si_m_endcol;
  676. /*
  677.  * Continue after the match (be aware of a zero-length
  678.  * match).
  679.  */
  680. if (found_m_endcol > current_col)
  681.     current_col = found_m_endcol;
  682. else
  683.     ++current_col;
  684. /* syn_current_attr() will have skipped the check for
  685.  * an item that ends here, need to do that now. */
  686. ++current_col;
  687. check_state_ends(
  688.     ml_get_buf(syn_buf, current_lnum, FALSE));
  689. --current_col;
  690.     }
  691.     else
  692. break;
  693. }
  694.     }
  695.     /*
  696.      * If a sync point was encountered, break here.
  697.      */
  698.     if (found_flags)
  699.     {
  700. /*
  701.  * Put the item that was specified by the sync point on the
  702.  * state stack.  If there was no item specified, make the
  703.  * state stack empty.
  704.  */
  705. ga_clear(&current_state);
  706. if (found_match_idx >= 0 &&
  707. push_current(found_match_idx) == OK)
  708.     update_si_attr(current_state.ga_len - 1);
  709. /*
  710.  * When using "grouphere", continue from the sync point
  711.  * match, until the end of the line.  Parsing starts at
  712.  * the next line.
  713.  * For "groupthere" the parsing starts at start_lnum.
  714.  */
  715. if (found_flags & HL_SYNC_HERE)
  716. {
  717.     if (current_state.ga_len)
  718.     {
  719. cur_si = &CUR_STATE(current_state.ga_len - 1);
  720. cur_si->si_h_startcol = found_current_col;
  721. line = ml_get_buf(syn_buf, current_lnum, FALSE);
  722. update_si_end(cur_si, line, current_col);
  723.     }
  724.     current_col = found_m_endcol;
  725.     current_lnum = found_current_lnum;
  726.     (void)syn_finish_line(FALSE);
  727.     ++current_lnum;
  728. }
  729. else
  730.     current_lnum = start_lnum;
  731. break;
  732.     }
  733.     end_lnum = lnum;
  734.     invalidate_current_state();
  735. }
  736. /* Ran into start of the file or exceeded maximum number of lines */
  737. if (lnum <= break_lnum)
  738. {
  739.     invalidate_current_state();
  740.     current_lnum = break_lnum + 1;
  741. }
  742.     }
  743.     validate_current_state();
  744. }
  745. /*
  746.  * Return TRUE if the line-continuation pattern matches in line "lnum".
  747.  */
  748.     static int
  749. syn_match_linecont(lnum)
  750.     linenr_t     lnum;
  751. {
  752.     if (syn_buf->b_syn_linecont_prog != NULL)
  753.     {
  754. reg_ic = syn_buf->b_syn_linecont_ic;
  755. return syn_regexec(syn_buf->b_syn_linecont_prog,
  756.       ml_get_buf(syn_buf, lnum, FALSE), TRUE);
  757.     }
  758.     return FALSE;
  759. }
  760. /*
  761.  * Set the state for the start of a line.
  762.  */
  763.     static void
  764. syn_start_line()
  765. {
  766.     char_u *line;
  767.     struct state_item *cur_si;
  768.     int i;
  769.     current_finished = FALSE;
  770.     current_col = 0;
  771.     /*
  772.      * Need to update the end of a start/skip/end that continues from the
  773.      * previous line.  And regions that have "keepend", because they may
  774.      * influence contained items.
  775.      * Then check for items ending in column 0.
  776.      */
  777.     if (current_state.ga_len)
  778.     {
  779. line = ml_get_buf(syn_buf, current_lnum, FALSE);
  780. for (i = 0; i < current_state.ga_len; ++i)
  781. {
  782.     cur_si = &CUR_STATE(i);
  783.     if ((cur_si->si_flags & HL_KEEPEND)
  784.      || i == current_state.ga_len - 1)
  785.     {
  786. cur_si->si_h_startcol = 0; /* start highl. in col 0 */
  787. update_si_end(cur_si, line, 0);
  788.     }
  789. }
  790. check_state_ends(line);
  791.     }
  792.     next_match_idx = -1;
  793.     ++current_line_id;
  794. }
  795. /*
  796.  * Free b_syn_states[] for buffer "buf".
  797.  */
  798.     static void
  799. syn_free_all_states(buf)
  800.     BUF     *buf;
  801. {
  802.     int     idx;
  803.     if (buf->b_syn_states != NULL)
  804.     {
  805. for (idx = 0; idx < buf->b_syn_states_len; ++idx)
  806.     ga_clear(&(buf->b_syn_states[idx].sst_ga));
  807. vim_free(buf->b_syn_states);
  808. buf->b_syn_states = NULL;
  809. buf->b_syn_states_len = 0;
  810.     }
  811. }
  812. /*
  813.  * clear the entries in b_syn_states[] from "start" to (not including) "end"
  814.  */
  815.     static void
  816. syn_clear_states(start, end)
  817.     int start, end;
  818. {
  819.     int idx;
  820.     struct growarray *sp;
  821.     for (idx = start; idx < end; ++idx)
  822.     {
  823. sp = &(syn_buf->b_syn_states[idx].sst_ga);
  824. ga_clear(sp);
  825. sp->ga_itemsize = 0;
  826.     }
  827. }
  828. /*
  829.  * Try saving the current state in b_syn_states[].
  830.  * The current state must be at the start of the current_lnum line!
  831.  */
  832.     static void
  833. store_current_state()
  834. {
  835.     long idx;
  836.     int i;
  837.     struct growarray *to;
  838.     idx = current_lnum - syn_buf->b_syn_states_lnum;
  839.     if (idx >= 0 && idx < syn_buf->b_syn_states_len)
  840.     {
  841. to = &(syn_buf->b_syn_states[idx].sst_ga);
  842. if (to->ga_data != NULL)
  843.     ga_clear(to);
  844. else if (to->ga_itemsize == 0)
  845. {
  846.     to->ga_itemsize = sizeof(struct buf_state);
  847.     to->ga_growsize = 3;
  848. }
  849. if (current_state.ga_len && ga_grow(to, current_state.ga_len) != FAIL)
  850. {
  851.     for (i = 0; i < current_state.ga_len; ++i)
  852.     {
  853. SYN_STATE_P(to)[i].bs_idx = CUR_STATE(i).si_idx;
  854. SYN_STATE_P(to)[i].bs_flags = CUR_STATE(i).si_flags;
  855.     }
  856.     to->ga_len = current_state.ga_len;
  857.     to->ga_room -= to->ga_len;
  858. }
  859. syn_buf->b_syn_states[idx].sst_next_list = current_next_list;
  860. syn_buf->b_syn_states[idx].sst_next_flags = current_next_flags;
  861.     }
  862.     current_state_stored = TRUE;
  863. }
  864. /*
  865.  * Copy a state stack from "from" in b_syn_states[] to current_state;
  866.  */
  867.     static void
  868. copy_state_to_current(from)
  869.     struct syn_state *from;
  870. {
  871.     int     i;
  872.     struct growarray *ga = &(from->sst_ga);
  873.     ga_clear(&current_state);
  874.     validate_current_state();
  875.     keepend_level = -1;
  876.     if (ga->ga_len && ga_grow(&current_state, ga->ga_len) != FAIL)
  877.     {
  878. for (i = 0; i < ga->ga_len; ++i)
  879. {
  880.     CUR_STATE(i).si_idx = SYN_STATE_P(ga)[i].bs_idx;
  881.     CUR_STATE(i).si_flags = SYN_STATE_P(ga)[i].bs_flags;
  882.     if (keepend_level < 0 && (CUR_STATE(i).si_flags & HL_KEEPEND))
  883. keepend_level = i;
  884.     CUR_STATE(i).si_m_endcol = 0;
  885.     CUR_STATE(i).si_m_startcol = 0;
  886.     CUR_STATE(i).si_m_lnum = 0;
  887.     update_si_attr(i);
  888. }
  889. current_state.ga_len = ga->ga_len;
  890. current_state.ga_room -= current_state.ga_len;
  891.     }
  892.     current_next_list = from->sst_next_list;
  893.     current_next_flags = from->sst_next_flags;
  894. }
  895.     static void
  896. invalidate_current_state()
  897. {
  898.     ga_clear(&current_state);
  899.     current_state.ga_itemsize = 0;
  900.     current_next_list = NULL;
  901.     keepend_level = -1;
  902. }
  903.     static void
  904. validate_current_state()
  905. {
  906.     current_state.ga_itemsize = sizeof(struct state_item);
  907.     current_state.ga_growsize = 3;
  908. }
  909. /*
  910.  * Move a state stack from b_syn_states[from] to b_syn_states[to].
  911.  */
  912.     static void
  913. move_state(from, to)
  914.     int     from, to;
  915. {
  916.     ga_clear(&(syn_buf->b_syn_states[to].sst_ga));
  917.     syn_buf->b_syn_states[to] = syn_buf->b_syn_states[from];
  918.     ga_init(&(syn_buf->b_syn_states[from].sst_ga));
  919.     syn_buf->b_syn_states[from].sst_ga.ga_itemsize = 0; /* invalid entry */
  920. }
  921. /*
  922.  * Mark like "lnum" and following ones as changed: Need to recompute its
  923.  * highlighting.
  924.  * This must be called whenever something is changed.  ml_delete() and
  925.  * ml_append() take care of this when deleting/appending lines.
  926.  * When changing a single line, and calling update_screenline(), for it, no
  927.  * need to call this (syntax_check_changed() will be used then).
  928.  */
  929.     void
  930. syn_changed(lnum)
  931.     linenr_t lnum;
  932. {
  933.     if (curbuf->b_syn_change_lnum > lnum)
  934. curbuf->b_syn_change_lnum = lnum;
  935. }
  936. /*
  937.  * Return TRUE if the syntax at start of lnum changed since last time.
  938.  * This will only be called just after get_syntax_attr for the previous line,
  939.  * to check if the next line needs to be redrawn too.
  940.  */
  941.     int
  942. syntax_check_changed(lnum)
  943.     linenr_t lnum;
  944. {
  945.     struct growarray *ssp;
  946.     int i;
  947.     int retval = TRUE;
  948.     long idx;
  949.     reg_syn = TRUE; /* let vim_regexec() know we're using syntax */
  950.     /*
  951.      * Check the state stack when:
  952.      * - lnum is just below the previously syntaxed line.
  953.      * - lnum is not before the lines with saved states.
  954.      * - lnum is not past the lines with saved states.
  955.      * - lnum is at or before the last changed line.
  956.      */
  957.     idx = lnum - syn_buf->b_syn_states_lnum;
  958.     if (VALID_STATE(&current_state) && lnum == current_lnum + 1 &&
  959.     idx >= 0 && idx < syn_buf->b_syn_states_len &&
  960.     lnum < syn_buf->b_syn_change_lnum)
  961.     {
  962. /*
  963.  * finish the previous line (needed when not all of the line was drawn)
  964.  */
  965. (void)syn_finish_line(FALSE);
  966. ssp = &(syn_buf->b_syn_states[idx].sst_ga);
  967. if (VALID_STATE(ssp)) /* entry is valid */
  968. {
  969.     /*
  970.      * Compare the current state with the previously saved state of
  971.      * the line.
  972.      */
  973.     if (ssp->ga_len == current_state.ga_len
  974.     && syn_buf->b_syn_states[idx].sst_next_list
  975.  == current_next_list)
  976.     {
  977. for (i = current_state.ga_len; --i >= 0; )
  978.     if (SYN_STATE_P(ssp)[i].bs_idx != CUR_STATE(i).si_idx)
  979. break;
  980. /*
  981.  * If still the same state, return FALSE, syntax didn't change.
  982.  */
  983. if (i < 0)
  984.     retval = FALSE;
  985.     }
  986. }
  987. /*
  988.  * Store the current state in b_syn_states[] for later use.
  989.  */
  990. ++current_lnum;
  991. store_current_state();
  992.     }
  993.     reg_syn = FALSE;
  994.     /* If state has changed, the saved states are invalid now */
  995.     if (retval)
  996. syn_changed(lnum);
  997.     return retval;
  998. }
  999. /*
  1000.  * Finish the current line.
  1001.  * This doesn't return any attributes, it only gets the state at the end of
  1002.  * the line.  It can start anywhere in the line, as long as the current state
  1003.  * is valid.
  1004.  */
  1005.     static int
  1006. syn_finish_line(syncing)
  1007.     int     syncing; /* called for syncing */
  1008. {
  1009.     char_u *line;
  1010.     struct state_item *cur_si;
  1011.     if (!current_finished)
  1012.     {
  1013. line = ml_get_buf(syn_buf, current_lnum, FALSE);
  1014. while (!current_finished)
  1015. {
  1016.     (void)syn_current_attr(syncing, line);
  1017.     /*
  1018.      * When syncing, and found some item, need to check the item.
  1019.      */
  1020.     if (syncing && current_state.ga_len)
  1021.     {
  1022. /*
  1023.  * Check for match with sync item.
  1024.  */
  1025. cur_si = &CUR_STATE(current_state.ga_len - 1);
  1026. if (SYN_ITEMS(syn_buf)[cur_si->si_idx].sp_flags
  1027.        & (HL_SYNC_HERE|HL_SYNC_THERE))
  1028.     return TRUE;
  1029. /* syn_current_attr() will have skipped the check for an item
  1030.  * that ends here, need to do that now. */
  1031. ++current_col;
  1032. check_state_ends(line);
  1033. --current_col;
  1034.     }
  1035.     ++current_col;
  1036. }
  1037.     }
  1038.     return FALSE;
  1039. }
  1040. /*
  1041.  * Return highlight attributes for next character.
  1042.  * This function is alwyas called from the screen updating, for each
  1043.  * consecutive character.  And only after syntax_start() has been called for
  1044.  * the current line.
  1045.  * Note that "col" doesn't start at 0, when win->w_leftcol is non-zero, and
  1046.  * doesn't continue until the last col when 'nowrap' is set.
  1047.  */
  1048.     int
  1049. get_syntax_attr(col, line)
  1050.     colnr_t col;
  1051.     char_u *line;
  1052. {
  1053.     int     attr = 0;
  1054.     reg_syn = TRUE; /* let vim_regexec() know we're using syntax */
  1055.     /* check for out of memory situation */
  1056.     if (syn_buf->b_syn_states_len == 0)
  1057. return 0;
  1058.     /* Make sure current_state is valid */
  1059.     if (INVALID_STATE(&current_state))
  1060. validate_current_state();
  1061.     /*
  1062.      * Skip from the current column to "col", get the attributes for "col".
  1063.      */
  1064.     while (current_col <= col)
  1065.     {
  1066. attr = syn_current_attr(FALSE, line);
  1067. ++current_col;
  1068.     }
  1069.     reg_syn = FALSE;
  1070.     return attr;
  1071. }
  1072. /*
  1073.  * Get syntax attributes for current_lnum, current_col.
  1074.  */
  1075.     static int
  1076. syn_current_attr(syncing, line)
  1077.     int syncing;     /* When 1: called for syncing */
  1078.     char_u *line;
  1079. {
  1080.     int syn_id;
  1081.     char_u *endp;
  1082.     char_u *hl_endp = NULL;
  1083.     char_u *eoep;     /* end-of-end pattern */
  1084.     int end_idx;    /* group ID for end pattern */
  1085.     int idx;
  1086.     struct syn_pattern *spp;
  1087.     struct state_item *cur_si, *sip;
  1088.     int startcol;
  1089.     int hl_startcol;
  1090.     int eos_col;    /* end-of-start column */
  1091.     int endcol;
  1092.     int flags;
  1093.     short *next_list;
  1094.     int found_match;     /* found usable match */
  1095.     static int try_next_column = FALSE;    /* must try in next col */
  1096.     /*
  1097.      * No character, no attributes!  Past end of line?
  1098.      * Do try matching with an empty line (could be the start of a region).
  1099.      */
  1100.     if (*(line + current_col) == NUL && current_col != 0)
  1101.     {
  1102. /*
  1103.  * If we found a match after the last column, use it.
  1104.  */
  1105. if (next_match_idx >= 0 && next_match_col >= (int)current_col
  1106.   && next_match_col != MAXCOL)
  1107.     (void)push_next_match(NULL, line);
  1108. current_finished = TRUE;
  1109. current_state_stored = FALSE;
  1110. return 0;
  1111.     }
  1112.     /* if the next character is NUL, we will finish the line now */
  1113.     if (*(line + current_col) == NUL || *(line + current_col + 1) == NUL)
  1114.     {
  1115. current_finished = TRUE;
  1116. current_state_stored = FALSE;
  1117.     }
  1118.     /*
  1119.      * When in the previous column there was a match but it could not be used
  1120.      * (empty match or already matched in this column) need to try again in
  1121.      * the next column.
  1122.      */
  1123.     if (try_next_column)
  1124.     {
  1125. next_match_idx = -1;
  1126. try_next_column = FALSE;
  1127.     }
  1128.     /*
  1129.      * Repeat matching keywords and patterns, to find contained items at the
  1130.      * same column.  This stops when there are no extra matches at the current
  1131.      * column.
  1132.      */
  1133.     do
  1134.     {
  1135. found_match = FALSE;
  1136. syn_id = 0;
  1137. /*
  1138.  * 1. Check for a current state.
  1139.  *    Only when there is no current state, or if the current state may
  1140.  *    contain other things, we need to check for keywords and patterns.
  1141.  */
  1142. if (current_state.ga_len)
  1143.     cur_si = &CUR_STATE(current_state.ga_len - 1);
  1144. else
  1145.     cur_si = NULL;
  1146. if (cur_si == NULL || cur_si->si_cont_list != NULL)
  1147. {
  1148.     /*
  1149.      * 2. Check for keywords, if on a keyword char after a non-keyword
  1150.      *   char.  Don't do this when syncing.
  1151.      */
  1152.     if (       !syncing
  1153.     && (syn_buf->b_keywtab != NULL
  1154. || syn_buf->b_keywtab_ic != NULL)
  1155.     && vim_iswordc_buf(line[current_col], syn_buf)
  1156.     && (current_col == 0
  1157. || !vim_iswordc_buf(line[current_col - 1], syn_buf)))
  1158.     {
  1159. syn_id = check_keyword_id(line, (int)current_col,
  1160.  &endcol, &flags, &next_list, cur_si);
  1161. if (syn_id)
  1162. {
  1163.     if (push_current(KEYWORD_IDX) == OK)
  1164.     {
  1165. cur_si = &CUR_STATE(current_state.ga_len - 1);
  1166. cur_si->si_m_startcol = current_col;
  1167. cur_si->si_h_startcol = 0; /* starts right away */
  1168. cur_si->si_m_endcol = endcol;
  1169. cur_si->si_h_endcol = endcol;
  1170. cur_si->si_ends = TRUE;
  1171. cur_si->si_end_idx = 0;
  1172. cur_si->si_flags = flags;
  1173. cur_si->si_id = syn_id;
  1174. cur_si->si_trans_id = syn_id;
  1175. if (flags & HL_TRANSP)
  1176. {
  1177.     if (current_state.ga_len < 2)
  1178.     {
  1179. cur_si->si_attr = 0;
  1180. cur_si->si_trans_id = 0;
  1181.     }
  1182.     else
  1183.     {
  1184. cur_si->si_attr = CUR_STATE(
  1185. current_state.ga_len - 2).si_attr;
  1186. cur_si->si_trans_id = CUR_STATE(
  1187. current_state.ga_len - 2).si_trans_id;
  1188.     }
  1189. }
  1190. else
  1191.     cur_si->si_attr = syn_id2attr(syn_id);
  1192. cur_si->si_cont_list = NULL;
  1193. cur_si->si_next_list = next_list;
  1194. check_keepend();
  1195.     }
  1196.     else
  1197. vim_free(next_list);
  1198. }
  1199.     }
  1200.     /*
  1201.      * 3. Check for patterns (only if not found a keyword).
  1202.      */
  1203.     if (syn_id == 0 && syn_buf->b_syn_patterns.ga_len)
  1204.     {
  1205. /*
  1206.  * If we didn't check for a match yet, or we are past it, check
  1207.  * for any match with a pattern.
  1208.  */
  1209. if (next_match_idx < 0 || next_match_col < (int)current_col)
  1210. {
  1211.     /*
  1212.      * Check all relevant patterns for a match at this
  1213.      * position.
  1214.      */
  1215.     next_match_idx = 0; /* no match in this line yet */
  1216.     next_match_col = MAXCOL; /* no match in this line yet */
  1217.     for (idx = syn_buf->b_syn_patterns.ga_len; --idx >= 0; )
  1218.     {
  1219. spp = &(SYN_ITEMS(syn_buf)[idx]);
  1220. if (    spp->sp_syncing == syncing
  1221. && (spp->sp_type == SPTYPE_MATCH
  1222.     || spp->sp_type == SPTYPE_START)
  1223. && ((current_next_list != 0
  1224. && in_id_list(current_next_list,
  1225. spp->sp_syn_id,
  1226. spp->sp_syn_inc_lvl, 0))
  1227.     || (current_next_list == 0
  1228. && ((cur_si == NULL
  1229.     && !(spp->sp_flags & HL_CONTAINED))
  1230. || (cur_si != NULL
  1231.  && in_id_list(cur_si->si_cont_list,
  1232. spp->sp_syn_id,
  1233. spp->sp_syn_inc_lvl,
  1234.      spp->sp_flags & HL_CONTAINED))))))
  1235. {
  1236.     int lc_col;
  1237.     /* If we already tried matching in this line, and
  1238.      * there isn't a match before next_match_col, skip
  1239.      * this item. */
  1240.     if (spp->sp_line_id == current_line_id
  1241. && spp->sp_startcol >= next_match_col)
  1242. continue;
  1243.     spp->sp_line_id = current_line_id;
  1244.     lc_col = current_col - spp->sp_offsets[SPO_LC_OFF];
  1245.     if (lc_col < 0)
  1246. lc_col = 0;
  1247.     reg_ic = spp->sp_ic;
  1248.     if (!syn_regexec(spp->sp_prog, line + lc_col,
  1249.      lc_col == 0))
  1250.     {
  1251. spp->sp_startcol = MAXCOL;
  1252. continue;
  1253.     }
  1254.     /*
  1255.      * Compute the first column of the match.
  1256.      */
  1257.     startcol = syn_add_start_off(spp,
  1258.        SPO_MS_OFF, -1) - line;
  1259.     if (startcol < 0)
  1260. startcol = 0;
  1261.     spp->sp_startcol = startcol;
  1262.     /*
  1263.      * If an existing match is better, skip this one.
  1264.      */
  1265.     if (startcol >= next_match_col)
  1266. continue;
  1267.     /*
  1268.      * If we matched this pattern at this position
  1269.      * before, skip it.  Must retry in the next
  1270.      * column, because it may match from there..
  1271.      */
  1272.     if (did_match_already(idx))
  1273.     {
  1274. try_next_column = TRUE;
  1275. continue;
  1276.     }
  1277.     endp = spp->sp_prog->endp[0];
  1278.     /* Compute the highlight start. */
  1279.     hl_startcol = syn_add_start_off(spp,
  1280.        SPO_HS_OFF, -1) - line;
  1281.     /* Compute the region start. */
  1282.     /* Default is to use the end of the match. */
  1283.     if (spp->sp_off_flags & (1 << SPO_RS_OFF))
  1284. eos_col = (spp->sp_prog->startp[0] - line)
  1285.     + spp->sp_offsets[SPO_RS_OFF] - 1;
  1286.     else
  1287. eos_col = (endp - line) - 1
  1288. + spp->sp_offsets[SPO_RS_OFF];
  1289.     /*
  1290.      * If this is a oneline, the end must be found
  1291.      * in the same line too.
  1292.      */
  1293.     flags = 0;
  1294.     eoep = line; /* avoid warning */
  1295.     end_idx = 0;
  1296.     if (spp->sp_type == SPTYPE_START
  1297.     && (spp->sp_flags & HL_ONELINE))
  1298. endp = find_endp(idx, endp, endp == line,
  1299. &hl_endp, &flags, &eoep, &end_idx);
  1300.     /*
  1301.      * For a "match" the size must be > 0 after the
  1302.      * end offset needs has been added.  Except when
  1303.      * syncing.
  1304.      */
  1305.     else if (spp->sp_type == SPTYPE_MATCH)
  1306.     {
  1307. hl_endp = syn_add_end_off(spp, SPO_HE_OFF, 0);
  1308. endp = syn_add_end_off(spp, SPO_ME_OFF, 0);
  1309. if (endp + syncing <= line + startcol)
  1310. {
  1311.     /*
  1312.      * If an empty string is matched, may need
  1313.      * to try matching again at next column.
  1314.      */
  1315.     if (spp->sp_prog->startp[0] ==
  1316. spp->sp_prog->endp[0])
  1317. try_next_column = TRUE;
  1318.     continue;
  1319. }
  1320.     }
  1321.     /* keep the best match so far in next_match_* */
  1322.     if (endp != NULL)
  1323.     {
  1324. if (hl_startcol < startcol)
  1325.     hl_startcol = startcol;
  1326. if (hl_endp == NULL || hl_endp > endp)
  1327.     hl_endp = endp;
  1328. next_match_idx = idx;
  1329. next_match_col = startcol;
  1330. next_match_m_endcol = endp - line;
  1331. next_match_h_endcol = hl_endp - line;
  1332. next_match_h_startcol = hl_startcol;
  1333. next_match_flags = flags;
  1334. next_match_eos_col = eos_col;
  1335. next_match_eoe_col = eoep - line;
  1336. next_match_end_idx = end_idx;
  1337.     }
  1338. }
  1339.     }
  1340. }
  1341. /*
  1342.  * If we found a match at the current column, use it.
  1343.  */
  1344. if (next_match_idx >= 0 && next_match_col == (int)current_col)
  1345. {
  1346.     cur_si = push_next_match(cur_si, line);
  1347.     found_match = TRUE;
  1348. }
  1349.     }
  1350. }
  1351. /*
  1352.  * Handle searching for nextgroup match.
  1353.  */
  1354. if (current_next_list)
  1355. {
  1356.     /*
  1357.      * If a nextgroup was not found, continue looking for one if:
  1358.      * - this is an empty line and the "skipempty" option was given
  1359.      * - we are on white space and the "skipwhite" option was given
  1360.      */
  1361.     if (!found_match
  1362.     && (   ((current_next_flags & HL_SKIPWHITE)
  1363.     && vim_iswhite(line[current_col]))
  1364. || ((current_next_flags & HL_SKIPEMPTY)
  1365.     && *line == NUL)))
  1366. break;
  1367.     /*
  1368.      * If a nextgroup was found: Use it, and continue looking for
  1369.      * contained matches.
  1370.      * If a nextgroup was not found: Continue looking for a normal
  1371.      * match.
  1372.      */
  1373.     current_next_list = NULL;
  1374.     next_match_idx = -1;
  1375.     found_match = TRUE;
  1376. }
  1377.     } while (found_match);
  1378.     /*
  1379.      * Use attributes from the current state, if within its highlighting.
  1380.      * If not, use attributes from the current-but-one state, etc.
  1381.      */
  1382.     current_attr = 0;
  1383.     current_id = 0;
  1384.     current_trans_id = 0;
  1385.     if (cur_si != NULL)
  1386.     {
  1387. for (idx = current_state.ga_len - 1; idx >= 0; --idx)
  1388. {
  1389.     sip = &CUR_STATE(idx);
  1390.     if ((int)current_col >= sip->si_h_startcol
  1391.       && (int)current_col <= sip->si_h_endcol)
  1392.     {
  1393. current_attr = sip->si_attr;
  1394. current_id = sip->si_id;
  1395. current_trans_id = sip->si_trans_id;
  1396. break;
  1397.     }
  1398. }
  1399. /*
  1400.  * Check for end of current state (and the states before it) at the
  1401.  * next column.  Don't do this for syncing, because we would miss a
  1402.  * single character match.
  1403.  */
  1404. if (!syncing)
  1405. {
  1406.     ++current_col;
  1407.     check_state_ends(line);
  1408.     --current_col;
  1409. }
  1410.     }
  1411.     /* nextgroup ends at end of line, unless "skipnl" or "skipemtpy" present */
  1412.     if (current_next_list != NULL
  1413.     && line[current_col + 1] == NUL
  1414.     && !(current_next_flags & (HL_SKIPNL | HL_SKIPEMPTY)))
  1415. current_next_list = NULL;
  1416.     return current_attr;
  1417. }
  1418. /*
  1419.  * Check if we already matched pattern "idx" at the current column.
  1420.  */
  1421.     static int
  1422. did_match_already(idx)
  1423.     int     idx;
  1424. {
  1425.     int i;
  1426.     for (i = current_state.ga_len; --i >= 0; )
  1427.     {
  1428. if (CUR_STATE(i).si_m_startcol == (int)current_col
  1429. && CUR_STATE(i).si_m_lnum == (int)current_lnum
  1430. && CUR_STATE(i).si_idx == idx)
  1431.     return TRUE;
  1432.     }
  1433.     return FALSE;
  1434. }
  1435. /*
  1436.  * Push the next match onto the stack.
  1437.  */
  1438.     static struct state_item *
  1439. push_next_match(cur_si, line)
  1440.     struct state_item *cur_si;
  1441.     char_u *line;
  1442. {
  1443.     struct syn_pattern *spp;
  1444.     spp = &(SYN_ITEMS(syn_buf)[next_match_idx]);
  1445.     /*
  1446.      * Push the item in current_state stack;
  1447.      */
  1448.     if (push_current(next_match_idx) == OK)
  1449.     {
  1450. /*
  1451.  * If it's a start-skip-end type that crosses lines, figure out how
  1452.  * much it continues in this line.  Otherwise just fill in the length.
  1453.  */
  1454. cur_si = &CUR_STATE(current_state.ga_len - 1);
  1455. cur_si->si_h_startcol = next_match_h_startcol;
  1456. cur_si->si_m_startcol = current_col;
  1457. cur_si->si_m_lnum = current_lnum;
  1458. cur_si->si_flags = spp->sp_flags;
  1459. cur_si->si_next_list = spp->sp_next_list;
  1460. if (spp->sp_type == SPTYPE_START && !(spp->sp_flags & HL_ONELINE))
  1461. {
  1462.     update_si_end(cur_si, line, next_match_m_endcol);
  1463. }
  1464. else
  1465. {
  1466.     cur_si->si_m_endcol = next_match_m_endcol - 1;
  1467.     cur_si->si_h_endcol = next_match_h_endcol - 1;
  1468.     cur_si->si_ends = TRUE;
  1469.     cur_si->si_flags |= next_match_flags;
  1470.     cur_si->si_eoe_col = next_match_eoe_col;
  1471.     cur_si->si_end_idx = next_match_end_idx;
  1472. }
  1473. if (keepend_level < 0 && (cur_si->si_flags & HL_KEEPEND))
  1474.     keepend_level = current_state.ga_len - 1;
  1475. check_keepend();
  1476. update_si_attr(current_state.ga_len - 1);
  1477. /*
  1478.  * If the start pattern has another highlight group, push another item
  1479.  * on the stack for the start pattern.
  1480.  */
  1481. if (    spp->sp_type == SPTYPE_START
  1482. && spp->sp_syn_match_id != 0
  1483. && spp->sp_syn_id != spp->sp_syn_match_id
  1484. && push_current(next_match_idx) == OK)
  1485. {
  1486.     cur_si = &CUR_STATE(current_state.ga_len - 1);
  1487.     cur_si->si_h_startcol = next_match_h_startcol;
  1488.     cur_si->si_m_startcol = current_col;
  1489.     cur_si->si_m_lnum = current_lnum;
  1490.     cur_si->si_m_endcol = next_match_eos_col;
  1491.     cur_si->si_h_endcol = next_match_eos_col;
  1492.     cur_si->si_ends = TRUE;
  1493.     cur_si->si_end_idx = 0;
  1494.     cur_si->si_flags = HL_MATCH;
  1495.     cur_si->si_next_list = NULL;
  1496.     check_keepend();
  1497.     update_si_attr(current_state.ga_len - 1);
  1498. }
  1499.     }
  1500.     next_match_idx = -1; /* try other match next time */
  1501.     return cur_si;
  1502. }
  1503. /*
  1504.  * Check for end of current state (and the states before it).
  1505.  */
  1506.     static void
  1507. check_state_ends(line)
  1508.     char_u *line;
  1509. {
  1510.     struct state_item *cur_si;
  1511.     cur_si = &CUR_STATE(current_state.ga_len - 1);
  1512.     for (;;)
  1513.     {
  1514. if (cur_si->si_m_endcol < (int)current_col && cur_si->si_ends)
  1515. {
  1516.     /*
  1517.      * If there is an end pattern group ID, highlight the end pattern
  1518.      * now.  No need to pop the current item from the stack.
  1519.      * Only do this if the end pattern continuous beyond the current
  1520.      * position.
  1521.      */
  1522.     if (cur_si->si_end_idx && cur_si->si_eoe_col >= (int)current_col)
  1523.     {
  1524. cur_si->si_idx = cur_si->si_end_idx;
  1525. cur_si->si_end_idx = 0;
  1526. cur_si->si_m_endcol = cur_si->si_eoe_col;
  1527. cur_si->si_h_endcol = cur_si->si_eoe_col;
  1528. cur_si->si_flags |= HL_MATCH;
  1529. update_si_attr(current_state.ga_len - 1);
  1530. break;
  1531.     }
  1532.     else
  1533.     {
  1534. /* handle next_list, unless at end of line and no "skipnl" or
  1535.  * "skipempty" */
  1536. current_next_list = cur_si->si_next_list;
  1537. current_next_flags = cur_si->si_flags;
  1538. if (!(current_next_flags & (HL_SKIPNL | HL_SKIPEMPTY))
  1539. && line[current_col] == NUL)
  1540.     current_next_list = NULL;
  1541. pop_current();
  1542. if (current_state.ga_len == 0)
  1543.     break;
  1544. cur_si = &CUR_STATE(current_state.ga_len - 1);
  1545. /*
  1546.  * Only for a region the search for the end continues after
  1547.  * the end of the contained item.  If the contained match
  1548.  * included the end-of-line, break here, the region continues.
  1549.  * Don't do this when "keepend" is used.
  1550.  */
  1551. if (SYN_ITEMS(syn_buf)[cur_si->si_idx].sp_type == SPTYPE_START
  1552.      && !(cur_si->si_flags & (HL_MATCH | HL_KEEPEND)))
  1553. {
  1554.     update_si_end(cur_si, line, (int)current_col);
  1555.     if (current_next_flags & HL_HAS_EOL)
  1556. break;
  1557. }
  1558.     }
  1559. }
  1560. else
  1561.     break;
  1562.     }
  1563. }
  1564. /*
  1565.  * Update an entry in the current_state stack for a match or region.  This
  1566.  * fills in si_attr and si_cont_list.
  1567.  */
  1568.     static void
  1569. update_si_attr(idx)
  1570.     int     idx;
  1571. {
  1572.     struct state_item *sip = &CUR_STATE(idx);
  1573.     struct syn_pattern *spp;
  1574.     spp = &(SYN_ITEMS(syn_buf)[sip->si_idx]);
  1575.     if (sip->si_flags & HL_MATCH)
  1576. sip->si_id = spp->sp_syn_match_id;
  1577.     else
  1578. sip->si_id = spp->sp_syn_id;
  1579.     sip->si_attr = syn_id2attr(sip->si_id);
  1580.     sip->si_trans_id = sip->si_id;
  1581.     if (sip->si_flags & HL_MATCH)
  1582. sip->si_cont_list = NULL;
  1583.     else
  1584. sip->si_cont_list = spp->sp_cont_list;
  1585.     /*
  1586.      * For transparent items, take attr from outer item.
  1587.      * Also take cont_list, if there is none.
  1588.      * Don't do this for the matchgroup of a start or end pattern.
  1589.      */
  1590.     if ((spp->sp_flags & HL_TRANSP) && !(sip->si_flags & HL_MATCH))
  1591.     {
  1592. if (idx == 0)
  1593. {
  1594.     sip->si_attr = 0;
  1595.     sip->si_trans_id = 0;
  1596.     if (sip->si_cont_list == NULL)
  1597. sip->si_cont_list = ID_LIST_ALL;
  1598. }
  1599. else
  1600. {
  1601.     sip->si_attr = CUR_STATE(idx - 1).si_attr;
  1602.     sip->si_trans_id = CUR_STATE(idx - 1).si_trans_id;
  1603.     if (sip->si_cont_list == NULL)
  1604. sip->si_cont_list = CUR_STATE(idx - 1).si_cont_list;
  1605. }
  1606.     }
  1607. }
  1608. /*
  1609.  * Check the current stack for patterns with "keepend" flag.  Propagate the
  1610.  * match-end to contained items.
  1611.  */
  1612.     static void
  1613. check_keepend()
  1614. {
  1615.     int i;
  1616.     int maxend = MAXCOL;
  1617.     struct state_item *sip;
  1618.     /*
  1619.      * This check can consume a lot of time; only do it from the level where
  1620.      * there really is a keepend.
  1621.      */
  1622.     if (keepend_level < 0)
  1623. return;
  1624.     for (i = keepend_level; i < current_state.ga_len; ++i)
  1625.     {
  1626. sip = &CUR_STATE(i);
  1627. if (maxend < MAXCOL)
  1628. {
  1629.     if (sip->si_m_endcol > maxend)
  1630. sip->si_m_endcol = maxend;
  1631.     if (sip->si_h_endcol > maxend)
  1632. sip->si_h_endcol = maxend;
  1633.     if (sip->si_eoe_col > maxend)
  1634. sip->si_eoe_col = maxend;
  1635.     sip->si_ends = TRUE;
  1636. }
  1637. if (sip->si_ends && (sip->si_flags & HL_KEEPEND)
  1638.  && maxend > sip->si_m_endcol)
  1639.     maxend = sip->si_m_endcol;
  1640.     }
  1641. }
  1642. /*
  1643.  * Update an entry in the current_state stack for a start-skip-end pattern.
  1644.  * This finds the end of the current item, if it's in the current line.
  1645.  *
  1646.  * Return the flags for the matched END.
  1647.  */
  1648.     static void
  1649. update_si_end(sip, line, startcol)
  1650.     struct state_item *sip;
  1651.     char_u *line;
  1652.     int startcol;   /* where to start searching for the end */
  1653. {
  1654.     char_u *endp;
  1655.     char_u *hl_endp;
  1656.     char_u *end_endp;
  1657.     int end_idx;
  1658.     /*
  1659.      * We need to find the end of the match.  It may continue in the next
  1660.      * line.
  1661.      */
  1662.     end_idx = 0;
  1663.     endp = find_endp(sip->si_idx, line + startcol,
  1664.        startcol == 0, &hl_endp, &(sip->si_flags), &end_endp, &end_idx);
  1665.     if (endp == NULL)
  1666.     {
  1667. /* continues on next line */
  1668. if (SYN_ITEMS(syn_buf)[sip->si_idx].sp_flags & HL_ONELINE)
  1669. {
  1670.     sip->si_ends = TRUE;
  1671.     sip->si_m_endcol = STRLEN(line) - 1;
  1672. }
  1673. else
  1674. {
  1675.     sip->si_ends = FALSE;
  1676.     sip->si_m_endcol = MAXCOL;
  1677. }
  1678. sip->si_h_endcol = sip->si_m_endcol;
  1679.     }
  1680.     else
  1681.     {
  1682. /* match within this line */
  1683. sip->si_m_endcol = endp - line - 1;
  1684. sip->si_h_endcol = hl_endp - line - 1;
  1685. sip->si_ends = TRUE;
  1686. sip->si_eoe_col = end_endp - line - 1;
  1687. sip->si_end_idx = end_idx;
  1688.     }
  1689.     check_keepend();
  1690. }
  1691. /*
  1692.  * Add a new state to the current state stack.
  1693.  * Return FAIL if it's not possible (out of memory).
  1694.  */
  1695.     static int
  1696. push_current(idx)
  1697.     int     idx;
  1698. {
  1699.     if (ga_grow(&current_state, 1) == FAIL)
  1700. return FAIL;
  1701.     vim_memset(&CUR_STATE(current_state.ga_len), 0, sizeof(struct state_item));
  1702.     CUR_STATE(current_state.ga_len).si_idx = idx;
  1703.     ++current_state.ga_len;
  1704.     --current_state.ga_room;
  1705.     return OK;
  1706. }
  1707. /*
  1708.  * Remove a state from the current_state stack.
  1709.  */
  1710.     static void
  1711. pop_current()
  1712. {
  1713.     if (current_state.ga_len)
  1714.     {
  1715. --current_state.ga_len;
  1716. ++current_state.ga_room;
  1717.     }
  1718.     /* after the end of a pattern, try matching a keyword or pattern */
  1719.     next_match_idx = -1;
  1720.     /* if first state with "keepend" is popped, reset keepend_level */
  1721.     if (keepend_level >= current_state.ga_len)
  1722. keepend_level = -1;
  1723. }
  1724. /*
  1725.  * Find the end of a start/skip/end pattern match.
  1726.  */
  1727.     static char_u *
  1728. find_endp(idx, sstart, at_bol, hl_endp, flagsp, end_endp, end_idx)
  1729.     int     idx; /* index of the pattern */
  1730.     char_u  *sstart; /* where to start looking for an END match */
  1731.     int     at_bol; /* if sstart is at begin-of-line */
  1732.     char_u  **hl_endp; /* end column for highlighting */
  1733.     int     *flagsp; /* flags of matching END */
  1734.     char_u  **end_endp; /* end of end pattern match */
  1735.     int     *end_idx; /* group ID for end pattern match, or 0 */
  1736. {
  1737.     char_u *endp;     /* end of highlighting */
  1738.     struct syn_pattern *spp, *spp_skip;
  1739.     char_u *p;     /* end of match */
  1740.     int start_idx;
  1741.     int best_idx;
  1742.     char_u *best_ptr;
  1743.     /*
  1744.      * Check for being called with a START pattern.
  1745.      * Can happen with a match that continues to the next line, because it
  1746.      * contained a region.
  1747.      */
  1748.     spp = &(SYN_ITEMS(syn_buf)[idx]);
  1749.     if (spp->sp_type != SPTYPE_START)
  1750.     {
  1751. *hl_endp = sstart;
  1752. return sstart;
  1753.     }
  1754.     /*
  1755.      * Find the SKIP or first END pattern after the last START pattern.
  1756.      */
  1757.     for (;;)
  1758.     {
  1759. spp = &(SYN_ITEMS(syn_buf)[idx]);
  1760. if (spp->sp_type != SPTYPE_START)
  1761.     break;
  1762. ++idx;
  1763.     }
  1764.     /*
  1765.      * Lookup the SKIP pattern (if present)
  1766.      */
  1767.     if (spp->sp_type == SPTYPE_SKIP)
  1768.     {
  1769. spp_skip = spp;
  1770. ++idx;
  1771.     }
  1772.     else
  1773. spp_skip = NULL;
  1774.     endp = sstart;     /* start looking for a match at sstart */
  1775.     start_idx = idx;     /* remember the first END pattern. */
  1776.     for (;;)
  1777.     {
  1778. best_idx = -1;
  1779. best_ptr = NULL;
  1780. for (idx = start_idx; idx < syn_buf->b_syn_patterns.ga_len; ++idx)
  1781. {
  1782.     spp = &(SYN_ITEMS(syn_buf)[idx]);
  1783.     if (spp->sp_type != SPTYPE_END) /* past last END pattern */
  1784. break;
  1785.     reg_ic = spp->sp_ic;
  1786.     if (syn_regexec(spp->sp_prog, endp, (at_bol && endp == sstart)))
  1787.     {
  1788. if (best_idx == -1 || spp->sp_prog->startp[0] < best_ptr)
  1789. {
  1790.     best_idx = idx;
  1791.     best_ptr = spp->sp_prog->startp[0];
  1792. }
  1793.     }
  1794. }
  1795. /*
  1796.  * If all end patterns have been tried, and there is no match, the
  1797.  * item continues until end-of-line.
  1798.  */
  1799. if (best_idx == -1)
  1800.     break;
  1801. /*
  1802.  * If the skip pattern matches before the end pattern,
  1803.  * continue searching after the skip pattern.
  1804.  */
  1805. if (    spp_skip != NULL
  1806. && (reg_ic = spp_skip->sp_ic,
  1807. syn_regexec(spp_skip->sp_prog, endp,
  1808.   (at_bol && endp == sstart)))
  1809. && spp_skip->sp_prog->startp[0] <= best_ptr)
  1810. {
  1811.     /* Add offset to skip pattern match */
  1812.     p = syn_add_end_off(spp_skip, SPO_ME_OFF, 1);
  1813.     /* take care of an empty match or negative offset */
  1814.     if (p <= endp)
  1815. ++endp;
  1816.     else if (p <= spp_skip->sp_prog->endp[0])
  1817. endp = p;
  1818.     else
  1819. /* Be careful not to jump over the NUL at the end-of-line */
  1820. for (endp = spp_skip->sp_prog->endp[0];
  1821.      *endp != NUL && endp < p; ++endp)
  1822.     ;
  1823.     /* if skip pattern includes end-of-line, return here */
  1824.     if (*endp == NUL)
  1825. break;
  1826.     continue;     /* start with first end pattern again */
  1827. }
  1828. /*
  1829.  * Match from start pattern to end pattern.
  1830.  * Correct for match and highlight offset of end pattern.
  1831.  */
  1832. spp = &(SYN_ITEMS(syn_buf)[best_idx]);
  1833. p = syn_add_end_off(spp, SPO_ME_OFF, 1);
  1834. if (p < sstart)
  1835.     p = sstart;
  1836. endp = syn_add_end_off(spp, SPO_HE_OFF, 1);
  1837. if (endp < sstart)
  1838.     endp = sstart;
  1839. if (endp > p)
  1840.     endp = p;
  1841. *end_endp = endp;
  1842. /*
  1843.  * If the end group is highlighted differently, adjust the pointers.
  1844.  */
  1845. if (spp->sp_syn_match_id != spp->sp_syn_id && spp->sp_syn_match_id != 0)
  1846. {
  1847.     *end_idx = best_idx;
  1848.     if (spp->sp_off_flags & (1 << (SPO_RE_OFF + SPO_COUNT)))
  1849. endp = spp->sp_prog->endp[0] + spp->sp_offsets[SPO_RE_OFF];
  1850.     else
  1851. endp = spp->sp_prog->startp[0] + spp->sp_offsets[SPO_RE_OFF];
  1852.     if (endp < sstart)
  1853. endp = sstart;
  1854.     if (endp > p)
  1855. endp = p;
  1856.     p = endp;
  1857. }
  1858. else
  1859.     *end_idx = 0;
  1860. *hl_endp = endp;
  1861. *flagsp = spp->sp_flags;
  1862. return p;
  1863.     }
  1864.     return NULL; /* no match for an END pattern in this line */
  1865. }
  1866. /*
  1867.  * Add offset to matched text for end of match or highlight.
  1868.  */
  1869.     static char_u *
  1870. syn_add_end_off(spp, idx, extra)
  1871.     struct syn_pattern *spp;
  1872.     int idx;
  1873.     int extra;     /* extra chars for offset to start */
  1874. {
  1875.     if (spp->sp_off_flags & (1 << idx))
  1876. return spp->sp_prog->startp[0] + spp->sp_offsets[idx] + extra;
  1877.     return spp->sp_prog->endp[0] + spp->sp_offsets[idx];
  1878. }
  1879. /*
  1880.  * Add offset to matched text for start of match or highlight.
  1881.  */
  1882.     static char_u *
  1883. syn_add_start_off(spp, idx, extra)
  1884.     struct syn_pattern *spp;
  1885.     int idx;
  1886.     int extra;     /* extra chars for offset to end */
  1887. {
  1888.     if (spp->sp_off_flags & (1 << (idx + SPO_COUNT)))
  1889. return spp->sp_prog->endp[0] + spp->sp_offsets[idx] + extra;
  1890.     return spp->sp_prog->startp[0] + spp->sp_offsets[idx];
  1891. }
  1892. /*
  1893.  * Check one position in a line for a matching keyword.
  1894.  * The caller must check if a keyword can start at startcol.
  1895.  * Return it's ID if found, 0 otherwise.
  1896.  */
  1897.     static int
  1898. check_keyword_id(line, startcol, endcol, flags, next_list, cur_si)
  1899.     char_u *line;
  1900.     int startcol;   /* position in line to check for keyword */
  1901.     int *endcol;    /* last character of found keyword */
  1902.     int *flags;     /* flags of matching keyword */
  1903.     short **next_list; /* next_list of matching keyword */
  1904.     struct state_item *cur_si;    /* item at the top of the stack */
  1905. {
  1906.     struct keyentry *ktab;
  1907.     char_u     *p;
  1908.     int     round;
  1909.     int     hash;
  1910.     int     len;
  1911.     char_u     keyword[MAXKEYWLEN + 1]; /* assume max. keyword len is 80 */
  1912.     /* Find first character after the keyword */
  1913.     p = line + startcol;
  1914.     for (len = 1; vim_iswordc_buf(p[len], syn_buf); ++len)
  1915. ;
  1916.     if (len > MAXKEYWLEN)
  1917. return 0;
  1918.     /*
  1919.      * Must make a copy of the keyword, so we can add a NUL and make it
  1920.      * uppercase.
  1921.      */
  1922.     STRNCPY(keyword, p, len);
  1923.     keyword[len] = NUL;
  1924.     /*
  1925.      * Try twice:
  1926.      * 1. matching case
  1927.      * 2. ignoring case
  1928.      */
  1929.     for (round = 1; round <= 2; ++round)
  1930.     {
  1931. if ((round == 1 ? syn_buf->b_keywtab : syn_buf->b_keywtab_ic) == NULL)
  1932.     continue;
  1933. p = keyword;
  1934. hash = 0;
  1935. if (round == 1) /* match case */
  1936. {
  1937.     while (*p)
  1938. hash += *p++;
  1939.     ktab = syn_buf->b_keywtab[hash & KHASH_MASK];
  1940. }
  1941. else /* round == 2, ignore case */
  1942. {
  1943.     while (*p)
  1944.     {
  1945. hash += (*p = TO_LOWER(*p));
  1946. ++p;
  1947.     }
  1948.     ktab = syn_buf->b_keywtab_ic[hash & KHASH_MASK];
  1949. }
  1950. /*
  1951.  * Find keywords that match.
  1952.  * When current_next_list is non-zero accept only that group, otherwise:
  1953.  *  Accept a not-contained keyword at toplevel.
  1954.  *  Accept a keyword at other levels only if it is in the contains list.
  1955.  */
  1956. for ( ; ktab != NULL; ktab = ktab->next)
  1957.     if (   STRCMP(keyword, ktab->keyword) == 0
  1958. && (   (current_next_list != 0
  1959. && in_id_list(current_next_list, ktab->syn_id,
  1960.       ktab->syn_inc_lvl, 0))
  1961.     || (current_next_list == 0
  1962. && ((cur_si == NULL && !(ktab->flags & HL_CONTAINED))
  1963.     || (cur_si != NULL
  1964. && in_id_list(cur_si->si_cont_list,
  1965. ktab->syn_id,
  1966. ktab->syn_inc_lvl,
  1967. ktab->flags & HL_CONTAINED))))))
  1968.     {
  1969. *endcol = startcol + len - 1;
  1970. *flags = ktab->flags;
  1971. *next_list = ktab->next_list;
  1972. return ktab->syn_id;
  1973.     }
  1974.     }
  1975.     return 0;
  1976. }
  1977. /*
  1978.  * Handle ":syntax case" command.
  1979.  */
  1980. /* ARGSUSED */
  1981.     static void
  1982. syn_cmd_case(eap, syncing)
  1983.     EXARG *eap;
  1984.     int syncing;     /* not used */
  1985. {
  1986.     char_u *arg = eap->arg;
  1987.     char_u *next;
  1988.     eap->nextcmd = find_nextcmd(arg);
  1989.     if (eap->skip)
  1990. return;
  1991.     next = skiptowhite(arg);
  1992.     if (STRNICMP(arg, "match", 5) == 0 && next - arg == 5)
  1993. curbuf->b_syn_ic = FALSE;
  1994.     else if (STRNICMP(arg, "ignore", 6) == 0 && next - arg == 6)
  1995. curbuf->b_syn_ic = TRUE;
  1996.     else
  1997. EMSG2("Illegal argument: %s", arg);
  1998. }
  1999. /*
  2000.  * Clear all syntax info for one buffer.
  2001.  */
  2002.     void
  2003. syntax_clear(buf)
  2004.     BUF     *buf;
  2005. {
  2006.     int i;
  2007.     curbuf->b_syn_ic = FALSE;     /* Use case, by default */
  2008.     /* free the keywords */
  2009.     free_keywtab(buf->b_keywtab);
  2010.     buf->b_keywtab = NULL;
  2011.     free_keywtab(buf->b_keywtab_ic);
  2012.     buf->b_keywtab_ic = NULL;
  2013.     /* free the syntax patterns */
  2014.     for (i = buf->b_syn_patterns.ga_len; --i >= 0; )
  2015. syn_clear_pattern(buf, i);
  2016.     ga_clear(&buf->b_syn_patterns);
  2017.     /* free the syntax clusters */
  2018.     for (i = buf->b_syn_clusters.ga_len; --i >= 0; )
  2019. syn_clear_cluster(buf, i);
  2020.     ga_clear(&buf->b_syn_clusters);
  2021.     buf->b_syn_sync_flags = 0;
  2022.     buf->b_syn_sync_minlines = 0;
  2023.     buf->b_syn_sync_maxlines = 0;
  2024.     vim_free(buf->b_syn_linecont_prog);
  2025.     buf->b_syn_linecont_prog = NULL;
  2026.     vim_free(buf->b_syn_linecont_pat);
  2027.     buf->b_syn_linecont_pat = NULL;
  2028.     /* free the stored states */
  2029.     syn_free_all_states(buf);
  2030. }
  2031. /*
  2032.  * Clear syncing info for one buffer.
  2033.  */
  2034.     static void
  2035. syntax_sync_clear()
  2036. {
  2037.     int i;
  2038.     /* free the syntax patterns */
  2039.     for (i = curbuf->b_syn_patterns.ga_len; --i >= 0; )
  2040. if (SYN_ITEMS(curbuf)[i].sp_syncing)
  2041.     syn_remove_pattern(curbuf, i);
  2042.     curbuf->b_syn_sync_flags = 0;
  2043.     curbuf->b_syn_sync_minlines = 0;
  2044.     curbuf->b_syn_sync_maxlines = 0;
  2045.     vim_free(curbuf->b_syn_linecont_prog);
  2046.     curbuf->b_syn_linecont_prog = NULL;
  2047.     vim_free(curbuf->b_syn_linecont_pat);
  2048.     curbuf->b_syn_linecont_pat = NULL;
  2049. }
  2050. /*
  2051.  * Remove one pattern from the buffer's pattern list.
  2052.  */
  2053.     static void
  2054. syn_remove_pattern(buf, idx)
  2055.     BUF     *buf;
  2056.     int     idx;
  2057. {
  2058.     struct syn_pattern *spp;
  2059.     spp = &(SYN_ITEMS(buf)[idx]);
  2060.     syn_clear_pattern(buf, idx);
  2061.     mch_memmove(spp, spp + 1, sizeof(struct syn_pattern) *
  2062.       (buf->b_syn_patterns.ga_len - idx - 1));
  2063.     --buf->b_syn_patterns.ga_len;
  2064.     --buf->b_syn_patterns.ga_room;
  2065. }
  2066. /*
  2067.  * Clear and free one syntax pattern.  When clearing all, must be called from
  2068.  * last to first!
  2069.  */
  2070.     static void
  2071. syn_clear_pattern(buf, i)
  2072.     BUF     *buf;
  2073.     int     i;
  2074. {
  2075.     vim_free(SYN_ITEMS(buf)[i].sp_pattern);
  2076.     vim_free(SYN_ITEMS(buf)[i].sp_prog);
  2077.     /* Only free sp_cont_list and sp_next_list of first start pattern */
  2078.     if (i == 0 || SYN_ITEMS(buf)[i - 1].sp_type != SPTYPE_START)
  2079.     {
  2080. vim_free(SYN_ITEMS(buf)[i].sp_cont_list);
  2081. vim_free(SYN_ITEMS(buf)[i].sp_next_list);
  2082.     }
  2083. }
  2084. /*
  2085.  * Clear and free one syntax cluster.
  2086.  */
  2087.     static void
  2088. syn_clear_cluster(buf, i)
  2089.     BUF     *buf;
  2090.     int     i;
  2091. {
  2092.     vim_free(SYN_CLSTR(buf)[i].scl_name);
  2093.     vim_free(SYN_CLSTR(buf)[i].scl_name_u);
  2094.     vim_free(SYN_CLSTR(buf)[i].scl_list);
  2095. }
  2096. /*
  2097.  * Handle ":syntax clear" command.
  2098.  */
  2099.     static void
  2100. syn_cmd_clear(eap, syncing)
  2101.     EXARG *eap;
  2102.     int syncing;
  2103. {
  2104.     char_u *arg = eap->arg;
  2105.     char_u *arg_end;
  2106.     int id;
  2107.     eap->nextcmd = find_nextcmd(arg);
  2108.     if (eap->skip)
  2109. return;
  2110.     /*
  2111.      * We have to disable this within ":syn include @group filename",
  2112.      * because otherwise @group would get deleted.
  2113.      */
  2114.     if (curbuf->b_syn_topgrp != 0)
  2115. return;
  2116.     if (ends_excmd(*arg))
  2117.     {
  2118. /*
  2119.  * No argument: Clear all syntax items.
  2120.  */
  2121. if (syncing)
  2122.     syntax_sync_clear();
  2123. else
  2124.     syntax_clear(curbuf);
  2125.     }
  2126.     else
  2127.     {
  2128. /*
  2129.  * Clear the group IDs that are in the argument.
  2130.  */
  2131. while (!ends_excmd(*arg))
  2132. {
  2133.     arg_end = skiptowhite(arg);
  2134.     if (*arg == '@')
  2135.     {
  2136. id = syn_scl_namen2id(arg + 1, (int)(arg_end - arg - 1));
  2137. if (id == 0)
  2138. {
  2139.     EMSG2("No such syntax cluster: %s", arg);
  2140.     break;
  2141. }
  2142. else
  2143. {
  2144.     /*
  2145.      * We can't physically delete a cluster without changing
  2146.      * the IDs of other clusters, so we do the next best thing
  2147.      * and make it empty.
  2148.      */
  2149.     short scl_id = id - CLUSTER_ID_MIN;
  2150.     vim_free(SYN_CLSTR(curbuf)[scl_id].scl_list);
  2151.     SYN_CLSTR(curbuf)[scl_id].scl_list = NULL;
  2152. }
  2153.     }
  2154.     else
  2155.     {
  2156. id = syn_namen2id(arg, (int)(arg_end - arg));
  2157. if (id == 0)
  2158. {
  2159.     EMSG2("No such highlight group name: %s", arg);
  2160.     break;
  2161. }
  2162. else
  2163.     syn_clear_one(id, syncing);
  2164.     }
  2165.     arg = skipwhite(arg_end);
  2166. }
  2167.     }
  2168.     redraw_curbuf_later(NOT_VALID);
  2169. }
  2170. /*
  2171.  * Clear one syntax group for the current buffer.
  2172.  */
  2173.     static void
  2174. syn_clear_one(id, syncing)
  2175.     int     id;
  2176.     int     syncing;
  2177. {
  2178.     struct syn_pattern *spp;
  2179.     int idx;
  2180.     /* Clear keywords only when not ":syn sync clear group-name" */
  2181.     if (!syncing)
  2182.     {
  2183. (void)syn_clear_keyword(id, curbuf->b_keywtab);
  2184. (void)syn_clear_keyword(id, curbuf->b_keywtab_ic);
  2185.     }
  2186.     /* clear the patterns for "id" */
  2187.     for (idx = curbuf->b_syn_patterns.ga_len; --idx >= 0; )
  2188.     {
  2189. spp = &(SYN_ITEMS(curbuf)[idx]);
  2190. if (spp->sp_syn_id != id || spp->sp_syncing != syncing)
  2191.     continue;
  2192. syn_remove_pattern(curbuf, idx);
  2193.     }
  2194. }
  2195. /*
  2196.  * Handle ":syntax on" command.
  2197.  */
  2198. /* ARGSUSED */
  2199.     static void
  2200. syn_cmd_on(eap, syncing)
  2201.     EXARG *eap;
  2202.     int syncing; /* not used */
  2203. {
  2204.     eap->nextcmd = check_nextcmd(eap->arg);
  2205.     if (!eap->skip)
  2206. do_cmdline((char_u *)"so $VIM/syntax/syntax.vim",
  2207.    NULL, NULL, DOCMD_VERBOSE);
  2208. }
  2209. /*
  2210.  * Handle ":syntax off" command.
  2211.  */
  2212. /* ARGSUSED */
  2213.     static void
  2214. syn_cmd_off(eap, syncing)
  2215.     EXARG *eap;
  2216.     int syncing; /* not used */
  2217. {
  2218.     eap->nextcmd = check_nextcmd(eap->arg);
  2219.     if (!eap->skip)
  2220. do_cmdline((char_u *)"so $VIM/syntax/nosyntax.vim",
  2221.    NULL, NULL, DOCMD_VERBOSE);
  2222. }
  2223. /*
  2224.  * Handle ":syntax [list]" command: list current syntax words.
  2225.  */
  2226.     static void
  2227. syn_cmd_list(eap, syncing)
  2228.     EXARG *eap;
  2229.     int syncing;     /* when TRUE: list syncing items */
  2230. {
  2231.     char_u *arg = eap->arg;
  2232.     int id;
  2233.     char_u *arg_end;
  2234.     eap->nextcmd = find_nextcmd(arg);
  2235.     if (eap->skip)
  2236. return;
  2237.     if (!syntax_present(curbuf))
  2238.     {
  2239. MSG("No Syntax items defined for this buffer");
  2240. return;
  2241.     }
  2242.     if (syncing)
  2243.     {
  2244. if (curbuf->b_syn_sync_flags & SF_CCOMMENT)
  2245. {
  2246.     MSG_PUTS("syncing on C-style comments");
  2247.     if (curbuf->b_syn_sync_minlines || curbuf->b_syn_sync_maxlines)
  2248. syn_lines_msg();
  2249.     return;
  2250. }
  2251. else if (!(curbuf->b_syn_sync_flags & SF_MATCH))
  2252. {
  2253.     MSG_PUTS("syncing starts ");
  2254.     msg_outnum(curbuf->b_syn_sync_minlines);
  2255.     MSG_PUTS(" lines before top line");
  2256.     return;
  2257. }
  2258. MSG_PUTS_TITLE("n--- Syntax sync items ---");
  2259. if (curbuf->b_syn_sync_minlines || curbuf->b_syn_sync_maxlines)
  2260. {
  2261.     MSG_PUTS("nsyncing on items");
  2262.     syn_lines_msg();
  2263. }
  2264.     }
  2265.     else
  2266. MSG_PUTS_TITLE("n--- Syntax items ---");
  2267.     if (ends_excmd(*arg))
  2268.     {
  2269. /*
  2270.  * No argument: List all group IDs and all syntax clusters.
  2271.  */
  2272. for (id = 1; id <= highlight_ga.ga_len && !got_int; ++id)
  2273.     syn_list_one(id, syncing, FALSE);
  2274. for (id = 0; id < curbuf->b_syn_clusters.ga_len && !got_int; ++id)
  2275.     syn_list_cluster(id);
  2276.     }
  2277.     else
  2278.     {
  2279. /*
  2280.  * List the group IDs and syntax clusters that are in the argument.
  2281.  */
  2282. while (!ends_excmd(*arg) && !got_int)
  2283. {
  2284.     arg_end = skiptowhite(arg);
  2285.     if (*arg == '@')
  2286.     {
  2287. id = syn_scl_namen2id(arg + 1, (int)(arg_end - arg - 1));
  2288. if (id == 0)
  2289.     EMSG2("No such syntax cluster: %s", arg);
  2290. else
  2291.     syn_list_cluster(id - CLUSTER_ID_MIN);
  2292.     }
  2293.     else
  2294.     {
  2295. id = syn_namen2id(arg, (int)(arg_end - arg));
  2296. if (id == 0)
  2297.     EMSG2("No such highlight group name: %s", arg);
  2298. else
  2299.     syn_list_one(id, syncing, TRUE);
  2300.     }
  2301.     arg = skipwhite(arg_end);
  2302. }
  2303.     }
  2304.     eap->nextcmd = check_nextcmd(arg);
  2305. }
  2306.     static void
  2307. syn_lines_msg()
  2308. {
  2309.     MSG_PUTS("; ");
  2310.     if (curbuf->b_syn_sync_minlines)
  2311.     {
  2312. MSG_PUTS("minimal ");
  2313. msg_outnum(curbuf->b_syn_sync_minlines);
  2314. if (curbuf->b_syn_sync_maxlines)
  2315.     MSG_PUTS(", ");
  2316.     }
  2317.     if (curbuf->b_syn_sync_maxlines)
  2318.     {
  2319. MSG_PUTS("maximal ");
  2320. msg_outnum(curbuf->b_syn_sync_maxlines);
  2321.     }
  2322.     MSG_PUTS(" lines before top line");
  2323. }
  2324. static int  last_matchgroup;
  2325. /*
  2326.  * List one syntax item, for ":syntax" or "syntax list syntax_name".
  2327.  */
  2328.     static void
  2329. syn_list_one(id, syncing, link_only)
  2330.     int     id;
  2331.     int     syncing;     /* when TRUE: list syncing items */
  2332.     int     link_only;     /* when TRUE; list link-only too */
  2333. {
  2334.     int attr;
  2335.     int idx;
  2336.     int did_header = FALSE;
  2337.     struct syn_pattern *spp;
  2338.     attr = hl_attr(HLF_D); /* highlight like directories */
  2339.     /* list the keywords for "id" */
  2340.     if (!syncing)
  2341.     {
  2342. did_header = syn_list_keywords(id, curbuf->b_keywtab, FALSE, attr);
  2343. did_header = syn_list_keywords(id, curbuf->b_keywtab_ic,
  2344.     did_header, attr);
  2345.     }
  2346.     /* list the patterns for "id" */
  2347.     for (idx = 0; idx < curbuf->b_syn_patterns.ga_len && !got_int; ++idx)
  2348.     {
  2349. spp = &(SYN_ITEMS(curbuf)[idx]);
  2350. if (spp->sp_syn_id != id || spp->sp_syncing != syncing)
  2351.     continue;
  2352. (void)syn_list_header(did_header, 999, id);
  2353. did_header = TRUE;
  2354. last_matchgroup = 0;
  2355. if (spp->sp_type == SPTYPE_MATCH)
  2356. {
  2357.     put_pattern("match", ' ', spp, attr);
  2358.     msg_putchar(' ');
  2359. }
  2360. else if (spp->sp_type == SPTYPE_START)
  2361. {
  2362.     while (SYN_ITEMS(curbuf)[idx].sp_type == SPTYPE_START)
  2363. put_pattern("start", '=', &SYN_ITEMS(curbuf)[idx++], attr);
  2364.     if (SYN_ITEMS(curbuf)[idx].sp_type == SPTYPE_SKIP)
  2365. put_pattern("skip", '=', &SYN_ITEMS(curbuf)[idx++], attr);
  2366.     while (idx < curbuf->b_syn_patterns.ga_len
  2367.       && SYN_ITEMS(curbuf)[idx].sp_type == SPTYPE_END)
  2368. put_pattern("end", '=', &SYN_ITEMS(curbuf)[idx++], attr);
  2369.     --idx;
  2370.     msg_putchar(' ');
  2371. }
  2372. if (spp->sp_flags & HL_CONTAINED)
  2373. {
  2374.     msg_puts_attr((char_u *)"contained", attr);
  2375.     msg_putchar(' ');
  2376. }
  2377. if (spp->sp_flags & HL_ONELINE)
  2378. {
  2379.     msg_puts_attr((char_u *)"oneline", attr);
  2380.     msg_putchar(' ');
  2381. }
  2382. if (spp->sp_flags & HL_KEEPEND)
  2383. {
  2384.     msg_puts_attr((char_u *)"keepend", attr);
  2385.     msg_putchar(' ');
  2386. }
  2387. if (spp->sp_flags & HL_TRANSP)
  2388. {
  2389.     msg_puts_attr((char_u *)"transparent", attr);
  2390.     msg_putchar(' ');
  2391. }
  2392. if (spp->sp_cont_list != NULL)
  2393. {
  2394.     put_id_list((char_u *)"contains", spp->sp_cont_list, attr);
  2395. }
  2396. if (spp->sp_next_list != NULL)
  2397. {
  2398.     put_id_list((char_u *)"nextgroup", spp->sp_next_list, attr);
  2399.     if (spp->sp_flags & HL_SKIPWHITE)
  2400.     {
  2401. msg_puts_attr((char_u *)"skipwhite", attr);
  2402. msg_putchar(' ');
  2403.     }
  2404.     if (spp->sp_flags & HL_SKIPNL)
  2405.     {
  2406. msg_puts_attr((char_u *)"skipnl", attr);
  2407. msg_putchar(' ');
  2408.     }
  2409.     if (spp->sp_flags & HL_SKIPEMPTY)
  2410.     {
  2411. msg_puts_attr((char_u *)"skipempty", attr);
  2412. msg_putchar(' ');
  2413.     }
  2414. }
  2415. if (spp->sp_flags & (HL_SYNC_HERE|HL_SYNC_THERE))
  2416. {
  2417.     if (spp->sp_flags & HL_SYNC_HERE)
  2418. msg_puts_attr((char_u *)"grouphere", attr);
  2419.     else
  2420. msg_puts_attr((char_u *)"groupthere", attr);
  2421.     msg_putchar(' ');
  2422.     if (spp->sp_sync_idx >= 0)
  2423. msg_outtrans(HL_TABLE()[SYN_ITEMS(curbuf)
  2424.    [spp->sp_sync_idx].sp_syn_id - 1].sg_name);
  2425.     else
  2426. MSG_PUTS("NONE");
  2427.     msg_putchar(' ');
  2428. }
  2429.     }
  2430.     /* list the link, if there is one */
  2431.     if (HL_TABLE()[id - 1].sg_link && (did_header || link_only) && !got_int)
  2432.     {
  2433. (void)syn_list_header(did_header, 999, id);
  2434. msg_puts_attr((char_u *)"links to", attr);
  2435. msg_putchar(' ');
  2436. msg_outtrans(HL_TABLE()[HL_TABLE()[id - 1].sg_link - 1].sg_name);
  2437.     }
  2438. }
  2439. /*
  2440.  * List one syntax cluster, for ":syntax" or "syntax list syntax_name".
  2441.  */
  2442.     static void
  2443. syn_list_cluster(id)
  2444.     int id;
  2445. {
  2446.     int     endcol = 15;
  2447.     /* slight hack:  roughly duplicate the guts of syn_list_header() */
  2448.     msg_putchar('n');
  2449.     msg_outtrans(SYN_CLSTR(curbuf)[id].scl_name);
  2450.     if (msg_col >= endcol) /* output at least one space */
  2451. endcol = msg_col + 1;
  2452.     if (Columns <= endcol) /* avoid hang for tiny window */
  2453. endcol = Columns - 1;
  2454.     msg_advance(endcol);
  2455.     if (SYN_CLSTR(curbuf)[id].scl_list != NULL)
  2456.     {
  2457. put_id_list((char_u *)"cluster", SYN_CLSTR(curbuf)[id].scl_list,
  2458.     hl_attr(HLF_D));
  2459.     }
  2460.     else
  2461.     {
  2462. msg_puts_attr((char_u *)"cluster", hl_attr(HLF_D));
  2463. msg_puts((char_u *)"=NONE");
  2464.     }
  2465. }
  2466.     static void
  2467. put_id_list(name, list, attr)
  2468.     char_u *name;
  2469.     short *list;
  2470.     int attr;
  2471. {
  2472.     short *p;
  2473.     msg_puts_attr(name, attr);
  2474.     msg_putchar('=');
  2475.     for (p = list; *p; ++p)
  2476.     {
  2477. if (*p >= CONTAINS_ALLBUT && *p < CLUSTER_ID_MIN)
  2478. {
  2479.     if (p[1])
  2480. MSG_PUTS("ALLBUT");
  2481.     else
  2482. MSG_PUTS("ALL");
  2483. }
  2484. else if (*p >= CLUSTER_ID_MIN)
  2485. {
  2486.     short scl_id = *p - CLUSTER_ID_MIN;
  2487.     msg_putchar('@');
  2488.     msg_outtrans(SYN_CLSTR(curbuf)[scl_id].scl_name);
  2489. }
  2490. else
  2491.     msg_outtrans(HL_TABLE()[*p - 1].sg_name);
  2492. if (p[1])
  2493.     msg_putchar(',');
  2494.     }
  2495.     msg_putchar(' ');
  2496. }
  2497.     static void
  2498. put_pattern(s, c, spp, attr)
  2499.     char *s;
  2500.     int c;
  2501.     struct syn_pattern *spp;
  2502.     int attr;
  2503. {
  2504.     long n;
  2505.     int mask;
  2506.     int first;
  2507.     static char *sepchars = "/+=-#@"|'^&";
  2508.     int i;
  2509.     /* May have to write "matchgroup=group" */
  2510.     if (last_matchgroup != spp->sp_syn_match_id)
  2511.     {
  2512. last_matchgroup = spp->sp_syn_match_id;
  2513. msg_puts_attr((char_u *)"matchgroup", attr);
  2514. msg_putchar('=');
  2515. if (last_matchgroup == 0)
  2516.     msg_outtrans((char_u *)"NONE");
  2517. else
  2518.     msg_outtrans(HL_TABLE()[last_matchgroup - 1].sg_name);
  2519. msg_putchar(' ');
  2520.     }
  2521.     /* output the name of the pattern and an '=' or ' ' */
  2522.     msg_puts_attr((char_u *)s, attr);
  2523.     msg_putchar(c);
  2524.     /* output the pattern, in between a char that is not in the pattern */
  2525.     for (i = 0; vim_strchr(spp->sp_pattern, sepchars[i]) != NULL; )
  2526. if (sepchars[++i] == NUL)
  2527. {
  2528.     i = 0; /* no good char found, just use the first one */
  2529.     break;
  2530. }
  2531.     msg_putchar(sepchars[i]);
  2532.     msg_outtrans(spp->sp_pattern);
  2533.     msg_putchar(sepchars[i]);
  2534.     /* output any pattern options */
  2535.     first = TRUE;
  2536.     for (i = 0; i < SPO_COUNT; ++i)
  2537.     {
  2538. mask = (1 << i);
  2539. if (spp->sp_off_flags & (mask + (mask << SPO_COUNT)))
  2540. {
  2541.     if (!first)
  2542. msg_putchar(','); /* separate with commas */
  2543.     msg_puts((char_u *)spo_name_tab[i]);
  2544.     n = spp->sp_offsets[i];
  2545.     if (i != SPO_LC_OFF)
  2546.     {
  2547. if (spp->sp_off_flags & mask)
  2548.     msg_putchar('s');
  2549. else
  2550.     msg_putchar('e');
  2551. if (n > 0)
  2552.     msg_putchar('+');
  2553.     }
  2554.     if (n || i == SPO_LC_OFF)
  2555. msg_outnum(n);
  2556.     first = FALSE;
  2557. }
  2558.     }
  2559.     msg_putchar(' ');
  2560. }
  2561. /*
  2562.  * List or clear the keywords for one syntax group.
  2563.  * Return TRUE if the header has been printed.
  2564.  */
  2565.     static int
  2566. syn_list_keywords(id, ktabp, did_header, attr)
  2567.     int     id;
  2568.     struct keyentry **ktabp;
  2569.     int     did_header; /* header has already been printed */
  2570.     int     attr;
  2571. {
  2572.     int     i;
  2573.     int     outlen;
  2574.     struct keyentry *ktab;
  2575.     int     prev_contained = 0;
  2576.     short     *prev_next_list = NULL;
  2577.     int     prev_skipnl = 0;
  2578.     int     prev_skipwhite = 0;
  2579.     int     prev_skipempty = 0;
  2580.     if (ktabp == NULL)
  2581. return did_header;
  2582.     /*
  2583.      * Unfortunately, this list of keywords is not sorted on alphabet but on
  2584.      * hash value...
  2585.      */
  2586.     for (i = 0; i < KHASH_SIZE; ++i)
  2587.     {
  2588. for (ktab = ktabp[i]; ktab != NULL && !got_int; ktab = ktab->next)
  2589. {
  2590.     if (ktab->syn_id == id)
  2591.     {
  2592. if (prev_contained != (ktab->flags & HL_CONTAINED)
  2593. || prev_skipnl != (ktab->flags & HL_SKIPNL)
  2594. || prev_skipwhite != (ktab->flags & HL_SKIPWHITE)
  2595. || prev_skipempty != (ktab->flags & HL_SKIPEMPTY)
  2596. || prev_next_list != ktab->next_list)
  2597.     outlen = 9999;
  2598. else
  2599.     outlen = STRLEN(ktab->keyword);
  2600. /* output "contained" and "nextgroup" on each line */
  2601. if (syn_list_header(did_header, outlen, id))
  2602. {
  2603.     prev_contained = 0;
  2604.     prev_next_list = NULL;
  2605.     prev_skipnl = 0;
  2606.     prev_skipwhite = 0;
  2607.     prev_skipempty = 0;
  2608. }
  2609. did_header = TRUE;
  2610. if (prev_contained != (ktab->flags & HL_CONTAINED))
  2611. {
  2612.     msg_puts_attr((char_u *)"contained", attr);
  2613.     msg_putchar(' ');
  2614.     prev_contained = (ktab->flags & HL_CONTAINED);
  2615. }
  2616. if (ktab->next_list != prev_next_list)
  2617. {
  2618.     put_id_list((char_u *)"nextgroup", ktab->next_list, attr);
  2619.     msg_putchar(' ');
  2620.     prev_next_list = ktab->next_list;
  2621.     if (ktab->flags & HL_SKIPNL)
  2622.     {
  2623. msg_puts_attr((char_u *)"skipnl", attr);
  2624. msg_putchar(' ');
  2625. prev_skipnl = (ktab->flags & HL_SKIPNL);
  2626.     }
  2627.     if (ktab->flags & HL_SKIPWHITE)
  2628.     {
  2629. msg_puts_attr((char_u *)"skipwhite", attr);
  2630. msg_putchar(' ');
  2631. prev_skipwhite = (ktab->flags & HL_SKIPWHITE);
  2632.     }
  2633.     if (ktab->flags & HL_SKIPEMPTY)
  2634.     {
  2635. msg_puts_attr((char_u *)"skipempty", attr);
  2636. msg_putchar(' ');
  2637. prev_skipempty = (ktab->flags & HL_SKIPEMPTY);
  2638.     }
  2639. }
  2640. msg_outtrans(ktab->keyword);
  2641.     }
  2642. }
  2643.     }
  2644.     return did_header;
  2645. }
  2646.     static void
  2647. syn_clear_keyword(id, ktabp)
  2648.     int     id;
  2649.     struct keyentry **ktabp;
  2650. {
  2651.     int     i;
  2652.     struct keyentry *ktab;
  2653.     struct keyentry *ktab_prev;
  2654.     struct keyentry *ktab_next;
  2655.     if (ktabp == NULL)     /* no keywords present */
  2656. return;
  2657.     for (i = 0; i < KHASH_SIZE; ++i)
  2658.     {
  2659. ktab_prev = NULL;
  2660. for (ktab = ktabp[i]; ktab != NULL; )
  2661. {
  2662.     if (ktab->syn_id == id)
  2663.     {
  2664. ktab_next = ktab->next;
  2665. if (ktab_prev == NULL)
  2666.     ktabp[i] = ktab_next;
  2667. else
  2668.     ktab_prev->next = ktab_next;
  2669. vim_free(ktab);
  2670. ktab = ktab_next;
  2671.     }
  2672.     else
  2673.     {
  2674. ktab_prev = ktab;
  2675. ktab = ktab->next;
  2676.     }
  2677. }
  2678.     }
  2679. }
  2680. /*
  2681.  * Recursive function to free() a branch of a kwordtab.
  2682.  */
  2683.     static void
  2684. free_keywtab(ktabp)
  2685.     struct keyentry **ktabp;
  2686. {
  2687.     int     i;
  2688.     struct keyentry *ktab;
  2689.     struct keyentry *ktab_next;
  2690.     if (ktabp != NULL)
  2691.     {
  2692. for (i = 0; i < KHASH_SIZE; ++i)
  2693.     for (ktab = ktabp[i]; ktab != NULL; ktab = ktab_next)
  2694.     {
  2695. ktab_next = ktab->next;
  2696. vim_free(ktab);
  2697.     }
  2698. vim_free(ktabp);
  2699.     }
  2700. }
  2701. /*
  2702.  * Add a keyword to the list of keywords.
  2703.  */
  2704.     static void
  2705. add_keyword(name, id, flags, next_list)
  2706.     char_u *name;     /* name of keyword */
  2707.     int id;     /* group ID for this keyword */
  2708.     int flags;     /* flags for this keyword */
  2709.     short *next_list; /* nextgroup for this keyword */
  2710. {
  2711.     struct keyentry *ktab;
  2712.     struct keyentry ***ktabpp;
  2713.     char_u *p;
  2714.     int hash;
  2715.     ktab = (struct keyentry *)alloc(
  2716.        (int)(sizeof(struct keyentry) + STRLEN(name)));
  2717.     if (ktab == NULL)
  2718. return;
  2719.     STRCPY(ktab->keyword, name);
  2720.     ktab->syn_id = id;
  2721.     ktab->syn_inc_lvl = current_syn_inc_lvl;
  2722.     ktab->flags = flags;
  2723.     ktab->next_list = copy_id_list(next_list);
  2724.     if (curbuf->b_syn_ic)
  2725.     {
  2726. for (p = ktab->keyword; *p; ++p)
  2727.     *p = TO_LOWER(*p);
  2728. ktabpp = &curbuf->b_keywtab_ic;
  2729.     }
  2730.     else
  2731. ktabpp = &curbuf->b_keywtab;
  2732.     if (*ktabpp == NULL)
  2733.     {
  2734. *ktabpp = (struct keyentry **)alloc_clear(
  2735.        (int)(sizeof(struct keyentry *) * KHASH_SIZE));
  2736. if (*ktabpp == NULL)
  2737.     return;
  2738.     }
  2739.     hash = 0;
  2740.     for (p = ktab->keyword; *p; ++p)
  2741. hash += *p;
  2742.     hash &= KHASH_MASK;
  2743.     ktab->next = (*ktabpp)[hash];
  2744.     (*ktabpp)[hash] = ktab;
  2745. }
  2746. /*
  2747.  * Get the start and end of the group name argument.
  2748.  * Return a pointer to the first argument.
  2749.  * Return NULL if the end of the command was found instead of further args.
  2750.  */
  2751.     static char_u *
  2752. get_group_name(arg, name_end)
  2753.     char_u *arg; /* start of the argument */
  2754.     char_u **name_end; /* pointer to end of the name */
  2755. {
  2756.     char_u *rest;
  2757.     *name_end = skiptowhite(arg);
  2758.     rest = skipwhite(*name_end);
  2759.     /*
  2760.      * Check if there are enough arguments.  The first argument may be a
  2761.      * pattern, where '|' is allowed, so only check for NUL.
  2762.      */
  2763.     if (ends_excmd(*arg) || *rest == NUL)
  2764. return NULL;
  2765.     return rest;
  2766. }
  2767. /*
  2768.  * Check for syntax command option arguments.
  2769.  * This can be called at any place in the list of arguments, and just picks
  2770.  * out the arguments that are known.  Can be called several times in a row to
  2771.  * collect all options in between other arguments.
  2772.  * Return a pointer to the next argument (which isn't an option).
  2773.  * Return NULL for any error;
  2774.  */
  2775.     static char_u *
  2776. get_syn_options(arg, flagsp, sync_idx, cont_list, next_list)
  2777.     char_u *arg; /* next argument */
  2778.     int *flagsp; /* flags for contained and transpartent */
  2779.     int *sync_idx; /* syntax item for "grouphere" argument, NULL
  2780.    if not allowed */
  2781.     short **cont_list; /* group IDs for "contains" argument, NULL if
  2782.    not allowed */
  2783.     short **next_list; /* group IDs for "nextgroup" argument */
  2784. {
  2785.     int flags;
  2786.     char_u *gname_start, *gname;
  2787.     int syn_id;
  2788.     int len;
  2789.     int i;
  2790.     int fidx;
  2791.     static struct flag
  2792.     {
  2793. char *name;
  2794. int len;
  2795. int val;
  2796.     } flagtab[] = { {"contained",   9, HL_CONTAINED},
  2797.     {"oneline",     7, HL_ONELINE},
  2798.     {"keepend",     7, HL_KEEPEND},
  2799.     {"transparent", 11, HL_TRANSP},
  2800.     {"skipnl",     6, HL_SKIPNL},
  2801.     {"skipwhite",   9, HL_SKIPWHITE},
  2802.     {"skipempty",   9, HL_SKIPEMPTY},
  2803.     {"grouphere",   9, HL_SYNC_HERE},
  2804.     {"groupthere",  10, HL_SYNC_THERE},
  2805. };
  2806.     if (arg == NULL) /* already detected error */
  2807. return NULL;
  2808.     flags = *flagsp;
  2809.     for (;;)
  2810.     {
  2811. for (fidx = sizeof(flagtab) / sizeof(struct flag); --fidx >= 0; )
  2812. {
  2813.     len = flagtab[fidx].len;
  2814.     if (STRNICMP(arg, flagtab[fidx].name, len) == 0
  2815.     && (ends_excmd(arg[len]) || vim_iswhite(arg[len])))
  2816.     {
  2817. flags |= flagtab[fidx].val;
  2818. arg = skipwhite(arg + len);
  2819. if (flagtab[fidx].val == HL_SYNC_HERE
  2820. || flagtab[fidx].val == HL_SYNC_THERE)
  2821. {
  2822.     if (sync_idx == NULL)
  2823.     {
  2824. EMSG("group[t]here not accepted here");
  2825. return NULL;
  2826.     }
  2827.     gname_start = arg;
  2828.     arg = skiptowhite(arg);
  2829.     if (gname_start == arg)
  2830. return NULL;
  2831.     gname = vim_strnsave(gname_start, (int)(arg - gname_start));
  2832.     if (gname == NULL)
  2833. return NULL;
  2834.     if (STRCMP(gname, "NONE") == 0)
  2835. *sync_idx = NONE_IDX;
  2836.     else
  2837.     {
  2838. syn_id = syn_name2id(gname);
  2839. for (i = curbuf->b_syn_patterns.ga_len; --i >= 0; )
  2840.     if (SYN_ITEMS(curbuf)[i].sp_syn_id == syn_id
  2841. && SYN_ITEMS(curbuf)[i].sp_type == SPTYPE_START)
  2842.     {
  2843. *sync_idx = i;
  2844. break;
  2845.     }
  2846. if (i < 0)
  2847. {
  2848.     EMSG2("Didn't find region item for %s", gname);
  2849.     vim_free(gname);
  2850.     return NULL;
  2851. }
  2852.     }
  2853.     vim_free(gname);
  2854.     arg = skipwhite(arg);
  2855. }
  2856. break;
  2857.     }
  2858. }
  2859. if (fidx >= 0)
  2860.     continue;
  2861. if (STRNICMP(arg, "contains", 8) == 0
  2862. && (vim_iswhite(arg[8]) || arg[8] == '='))
  2863. {
  2864.     if (cont_list == NULL)
  2865.     {
  2866. EMSG("contains argument not accepted here");
  2867. return NULL;
  2868.     }
  2869.     if (get_id_list(&arg, 8, cont_list) == FAIL)
  2870. return NULL;
  2871. }
  2872. else if (STRNICMP(arg, "nextgroup", 9) == 0
  2873. && (vim_iswhite(arg[9]) || arg[9] == '='))
  2874. {
  2875.     if (get_id_list(&arg, 9, next_list) == FAIL)
  2876. return NULL;
  2877. }
  2878. else
  2879.     break;
  2880.     }
  2881.     *flagsp = flags;
  2882.     return arg;
  2883. }
  2884. /*
  2885.  * Adjustments to syntax item when declared in a ":syn include"'d file.
  2886.  * Set the contained flag, and if the item is not already contained, add it
  2887.  * to the specified top-level group, if any.
  2888.  */
  2889.     static void
  2890. syn_incl_toplevel(id, flagsp)
  2891.     int id;
  2892.     int *flagsp;
  2893. {
  2894.     if ((*flagsp & HL_CONTAINED) || curbuf->b_syn_topgrp == 0)
  2895. return;
  2896.     *flagsp |= HL_CONTAINED;
  2897.     if (curbuf->b_syn_topgrp >= CLUSTER_ID_MIN)
  2898.     {
  2899. /* We have to alloc this, because syn_combine_list() will free it. */
  2900. short     *grp_list = (short *)alloc((unsigned)(2 * sizeof(short)));
  2901. int     tlg_id = curbuf->b_syn_topgrp - CLUSTER_ID_MIN;
  2902. if (grp_list != NULL)
  2903. {
  2904.     grp_list[0] = id;
  2905.     grp_list[1] = 0;
  2906.     syn_combine_list(&SYN_CLSTR(curbuf)[tlg_id].scl_list, &grp_list,
  2907.  CLUSTER_ADD);
  2908. }
  2909.     }
  2910. }
  2911. /*
  2912.  * Handle ":syntax include [@{group-name}] filename" command.
  2913.  */
  2914. /* ARGSUSED */
  2915.     static void
  2916. syn_cmd_include(eap, syncing)
  2917.     EXARG *eap;
  2918.     int syncing;     /* not used */
  2919. {
  2920.     char_u *arg = eap->arg;
  2921.     int sgl_id = 1;
  2922.     char_u *group_name_end;
  2923.     char_u *rest;
  2924.     char_u *errormsg = NULL;
  2925.     int prev_toplvl_grp;
  2926.     eap->nextcmd = find_nextcmd(arg);
  2927.     if (eap->skip)
  2928. return;
  2929.     if (arg[0] == '@')
  2930.     {
  2931. ++arg;
  2932. rest = get_group_name(arg, &group_name_end);
  2933. if (rest == NULL)
  2934. {
  2935.     EMSG((char_u *)"Filename required");
  2936.     return;
  2937. }
  2938. sgl_id = syn_check_cluster(arg, (int)(group_name_end - arg));
  2939. /* separate_nextcmd() and expand_filename() depend on this */
  2940. eap->arg = rest;
  2941.     }
  2942.     /*
  2943.      * Everything that's left, up to the next command, should be the
  2944.      * filename to include.
  2945.      */
  2946.     eap->argt |= (XFILE | NOSPC);
  2947.     separate_nextcmd(eap);
  2948.     if (expand_filename(eap, syn_cmdlinep, &errormsg) == FAIL)
  2949.     {
  2950. if (errormsg != NULL)
  2951.     EMSG(errormsg);
  2952. return;
  2953.     }
  2954.     /*
  2955.      * Save and restore the existing top-level grouplist id and ":syn
  2956.      * include" level around the actual inclusion.
  2957.      */
  2958.     current_syn_inc_lvl++;
  2959.     prev_toplvl_grp = curbuf->b_syn_topgrp;