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

编辑器/阅读器

开发平台:

DOS

  1.     curbuf->b_syn_topgrp = sgl_id;
  2.     if (do_source(eap->arg, FALSE, FALSE) == FAIL)
  3. emsg2(e_notopen, eap->arg);
  4.     curbuf->b_syn_topgrp = prev_toplvl_grp;
  5.     current_syn_inc_lvl--;
  6. }
  7. /*
  8.  * Handle ":syntax keyword {group-name} [{option}] keyword .." command.
  9.  */
  10. /* ARGSUSED */
  11.     static void
  12. syn_cmd_keyword(eap, syncing)
  13.     EXARG *eap;
  14.     int syncing;     /* not used */
  15. {
  16.     char_u *arg = eap->arg;
  17.     char_u *group_name_end;
  18.     int syn_id;
  19.     char_u *rest;
  20.     char_u *keyword_copy;
  21.     char_u *p;
  22.     char_u *first_arg;
  23.     int round;
  24.     int flags = 0;
  25.     short *next_list = NULL;
  26.     rest = get_group_name(arg, &group_name_end);
  27.     if (rest != NULL)
  28.     {
  29. syn_id = syn_check_group(arg, (int)(group_name_end - arg));
  30. /* allocate a buffer, for removing the backslashes in the keyword */
  31. keyword_copy = alloc((unsigned)STRLEN(rest) + 1);
  32. if (keyword_copy != NULL)
  33. {
  34.     /*
  35.      * The options given apply to ALL keywords, so all options must be
  36.      * found before keywords can be created.
  37.      * round 1: collect the options.
  38.      * round 2: create the keywords.
  39.      */
  40.     first_arg = rest;
  41.     for (round = 1; round <= 2; ++round)
  42.     {
  43. /*
  44.  * Isolate each keyword and add an entry for it.
  45.  */
  46. for (rest = first_arg; rest != NULL && !ends_excmd(*rest);
  47.        rest = skipwhite(rest))
  48. {
  49.     rest = get_syn_options(rest, &flags, NULL,
  50.     NULL, &next_list);
  51.     if (rest == NULL || ends_excmd(*rest))
  52. break;
  53.     p = keyword_copy;
  54.     while (*rest && !vim_iswhite(*rest))
  55.     {
  56. if (*rest == '\' && rest[1] != NUL)
  57.     ++rest;
  58. *p++ = *rest++;
  59.     }
  60.     *p = NUL;
  61.     if (round == 2 && !eap->skip)
  62.     {
  63. for (p = vim_strchr(keyword_copy, '['); ; ++p)
  64. {
  65.     if (p != NULL)
  66. *p = NUL;
  67.     add_keyword(keyword_copy, syn_id, flags, next_list);
  68.     if (p == NULL || p[1] == NUL || p[1] == ']')
  69. break;
  70.     p[0] = p[1];
  71. }
  72.     }
  73. }
  74. if (round == 1)
  75.     syn_incl_toplevel(syn_id, &flags);
  76.     }
  77.     vim_free(keyword_copy);
  78. }
  79.     }
  80.     if (rest != NULL)
  81. eap->nextcmd = check_nextcmd(rest);
  82.     else
  83. EMSG2(e_invarg2, arg);
  84.     vim_free(next_list);
  85.     redraw_curbuf_later(NOT_VALID);
  86. }
  87. /*
  88.  * Handle ":syntax match {name} [{options}] {pattern} [{options}]".
  89.  *
  90.  * Also ":syntax sync match {name} [[grouphere | groupthere] {group-name}] .."
  91.  */
  92.     static void
  93. syn_cmd_match(eap, syncing)
  94.     EXARG *eap;
  95.     int syncing;     /* TRUE for ":syntax sync match .. " */
  96. {
  97.     char_u *arg = eap->arg;
  98.     char_u *group_name_end;
  99.     char_u *rest;
  100.     struct syn_pattern item; /* the item found in the line */
  101.     int syn_id;
  102.     int idx;
  103.     int flags = 0;
  104.     int sync_idx = 0;
  105.     short *cont_list = NULL;
  106.     short *next_list = NULL;
  107.     /* Isolate the group name, check for validity */
  108.     rest = get_group_name(arg, &group_name_end);
  109.     /* Get options before the pattern */
  110.     rest = get_syn_options(rest, &flags, syncing ? &sync_idx : NULL,
  111.       &cont_list, &next_list);
  112.     /* get the pattern. */
  113.     init_syn_patterns();
  114.     vim_memset(&item, 0, sizeof(item));
  115.     rest = get_syn_pattern(rest, &item);
  116.     if (vim_regcomp_had_eol())
  117. flags |= HL_HAS_EOL;
  118.     /* Get options after the pattern */
  119.     rest = get_syn_options(rest, &flags, syncing ? &sync_idx : NULL,
  120.       &cont_list, &next_list);
  121.     if (rest != NULL) /* all arguments are valid */
  122.     {
  123. /*
  124.  * Check for trailing command and illegal trailing arguments.
  125.  */
  126. eap->nextcmd = check_nextcmd(rest);
  127. if (!ends_excmd(*rest) || eap->skip)
  128.     rest = NULL;
  129. else if (ga_grow(&curbuf->b_syn_patterns, 1) != FAIL
  130. && (syn_id = syn_check_group(arg,
  131.    (int)(group_name_end - arg))) != 0)
  132. {
  133.     syn_incl_toplevel(syn_id, &flags);
  134.     /*
  135.      * Store the pattern in the syn_items list
  136.      */
  137.     idx = curbuf->b_syn_patterns.ga_len;
  138.     SYN_ITEMS(curbuf)[idx] = item;
  139.     SYN_ITEMS(curbuf)[idx].sp_syncing = syncing;
  140.     SYN_ITEMS(curbuf)[idx].sp_type = SPTYPE_MATCH;
  141.     SYN_ITEMS(curbuf)[idx].sp_syn_id = syn_id;
  142.     SYN_ITEMS(curbuf)[idx].sp_syn_inc_lvl = current_syn_inc_lvl;
  143.     SYN_ITEMS(curbuf)[idx].sp_flags = flags;
  144.     SYN_ITEMS(curbuf)[idx].sp_sync_idx = sync_idx;
  145.     SYN_ITEMS(curbuf)[idx].sp_cont_list = cont_list;
  146.     SYN_ITEMS(curbuf)[idx].sp_next_list = next_list;
  147.     ++curbuf->b_syn_patterns.ga_len;
  148.     --curbuf->b_syn_patterns.ga_room;
  149.     /* remember that we found a match for syncing on */
  150.     if (flags & (HL_SYNC_HERE|HL_SYNC_THERE))
  151. curbuf->b_syn_sync_flags |= SF_MATCH;
  152.     redraw_curbuf_later(NOT_VALID);
  153.     return; /* don't free the progs and patterns now */
  154. }
  155.     }
  156.     /*
  157.      * Something failed, free the allocated memory.
  158.      */
  159.     vim_free(item.sp_prog);
  160.     vim_free(item.sp_pattern);
  161.     vim_free(cont_list);
  162.     vim_free(next_list);
  163.     if (rest == NULL)
  164. EMSG2(e_invarg2, arg);
  165. }
  166. /*
  167.  * Handle ":syntax region {group-name} [matchgroup={group-name}]
  168.  * start {start} .. [skip {skip}] end {end} .. [{options}]".
  169.  */
  170.     static void
  171. syn_cmd_region(eap, syncing)
  172.     EXARG *eap;
  173.     int syncing;     /* TRUE for ":syntax sync region .." */
  174. {
  175.     char_u *arg = eap->arg;
  176.     char_u *group_name_end;
  177.     char_u *rest; /* next arg, NULL on error */
  178.     char_u *key_end;
  179.     char_u *key = NULL;
  180.     char_u *p;
  181.     int item;
  182. #define ITEM_START     0
  183. #define ITEM_SKIP     1
  184. #define ITEM_END     2
  185. #define ITEM_MATCHGROUP     3
  186.     struct pat_ptr
  187.     {
  188. struct syn_pattern  *pp_synp; /* pointer to syn_pattern */
  189. int     pp_matchgroup_id; /* matchgroup ID */
  190. struct pat_ptr     *pp_next; /* pointer to next pat_ptr */
  191.     } *(pat_ptrs[3]);
  192.     /* patterns found in the line */
  193.     struct pat_ptr *ppp;
  194.     struct pat_ptr *ppp_next;
  195.     int pat_count = 0;     /* number of syn_patterns found */
  196.     int syn_id;
  197.     int matchgroup_id = 0;
  198.     int not_enough = FALSE; /* not enough arguments */
  199.     int illegal = FALSE; /* illegal arguments */
  200.     int success = FALSE;
  201.     int idx;
  202.     int flags = 0;
  203.     short *cont_list = NULL;
  204.     short *next_list = NULL;
  205.     /* Isolate the group name, check for validity */
  206.     rest = get_group_name(arg, &group_name_end);
  207.     pat_ptrs[0] = NULL;
  208.     pat_ptrs[1] = NULL;
  209.     pat_ptrs[2] = NULL;
  210.     init_syn_patterns();
  211.     /*
  212.      * get the options, patterns and matchgroup.
  213.      */
  214.     while (rest != NULL && !ends_excmd(*rest))
  215.     {
  216. /* Check for option arguments */
  217. rest = get_syn_options(rest, &flags, NULL, &cont_list, &next_list);
  218. if (rest == NULL || ends_excmd(*rest))
  219.     break;
  220. /* must be a pattern or matchgroup then */
  221. key_end = rest;
  222. while (*key_end && !vim_iswhite(*key_end) && *key_end != '=')
  223.     ++key_end;
  224. vim_free(key);
  225. key = vim_strnsave_up(rest, (int)(key_end - rest));
  226. if (key == NULL) /* out of memory */
  227. {
  228.     rest = NULL;
  229.     break;
  230. }
  231. if (STRCMP(key, "MATCHGROUP") == 0)
  232.     item = ITEM_MATCHGROUP;
  233. else if (STRCMP(key, "START") == 0)
  234.     item = ITEM_START;
  235. else if (STRCMP(key, "END") == 0)
  236.     item = ITEM_END;
  237. else if (STRCMP(key, "SKIP") == 0)
  238. {
  239.     if (pat_ptrs[ITEM_SKIP] != NULL) /* one skip pattern allowed */
  240.     {
  241. illegal = TRUE;
  242. break;
  243.     }
  244.     item = ITEM_SKIP;
  245. }
  246. else
  247.     break;
  248. rest = skipwhite(key_end);
  249. if (*rest != '=')
  250. {
  251.     rest = NULL;
  252.     EMSG2("Missing '=': %s", arg);
  253.     break;
  254. }
  255. rest = skipwhite(rest + 1);
  256. if (*rest == NUL)
  257. {
  258.     not_enough = TRUE;
  259.     break;
  260. }
  261. if (item == ITEM_MATCHGROUP)
  262. {
  263.     p = skiptowhite(rest);
  264.     if ((p - rest == 4 && STRNCMP(rest, "NONE", 4) == 0) || eap->skip)
  265. matchgroup_id = 0;
  266.     else
  267.     {
  268. matchgroup_id = syn_check_group(rest, (int)(p - rest));
  269. if (matchgroup_id == 0)
  270. {
  271.     illegal = TRUE;
  272.     break;
  273. }
  274.     }
  275.     rest = skipwhite(p);
  276. }
  277. else
  278. {
  279.     /*
  280.      * Allocate room for a syn_pattern, and link it in the list of
  281.      * syn_patterns for this item, at the start (because the list is
  282.      * used from end to start).
  283.      */
  284.     ppp = (struct pat_ptr *)alloc((unsigned)sizeof(struct pat_ptr));
  285.     if (ppp == NULL)
  286.     {
  287. rest = NULL;
  288. break;
  289.     }
  290.     ppp->pp_next = pat_ptrs[item];
  291.     pat_ptrs[item] = ppp;
  292.     ppp->pp_synp = (struct syn_pattern *)alloc_clear(
  293. (unsigned)sizeof(struct syn_pattern));
  294.     if (ppp->pp_synp == NULL)
  295.     {
  296. rest = NULL;
  297. break;
  298.     }
  299.     /*
  300.      * Get the syntax pattern and the following offset(s).
  301.      */
  302.     rest = get_syn_pattern(rest, ppp->pp_synp);
  303.     if (item == ITEM_END && vim_regcomp_had_eol())
  304. ppp->pp_synp->sp_flags |= HL_HAS_EOL;
  305.     ppp->pp_matchgroup_id = matchgroup_id;
  306.     ++pat_count;
  307. }
  308.     }
  309.     vim_free(key);
  310.     if (illegal || not_enough)
  311. rest = NULL;
  312.     /*
  313.      * Must have a "start" and "end" pattern.
  314.      */
  315.     if (rest != NULL && (pat_ptrs[ITEM_START] == NULL ||
  316.   pat_ptrs[ITEM_END] == NULL))
  317.     {
  318. not_enough = TRUE;
  319. rest = NULL;
  320.     }
  321.     if (rest != NULL)
  322.     {
  323. /*
  324.  * Check for trailing garbage or command.
  325.  * If OK, add the item.
  326.  */
  327. eap->nextcmd = check_nextcmd(rest);
  328. if (!ends_excmd(*rest) || eap->skip)
  329.     rest = NULL;
  330. else if (ga_grow(&(curbuf->b_syn_patterns), pat_count) != FAIL
  331. && (syn_id = syn_check_group(arg,
  332.    (int)(group_name_end - arg))) != 0)
  333. {
  334.     syn_incl_toplevel(syn_id, &flags);
  335.     /*
  336.      * Store the start/skip/end in the syn_items list
  337.      */
  338.     idx = curbuf->b_syn_patterns.ga_len;
  339.     for (item = ITEM_START; item <= ITEM_END; ++item)
  340.     {
  341. for (ppp = pat_ptrs[item]; ppp != NULL; ppp = ppp->pp_next)
  342. {
  343.     SYN_ITEMS(curbuf)[idx] = *(ppp->pp_synp);
  344.     SYN_ITEMS(curbuf)[idx].sp_syncing = syncing;
  345.     SYN_ITEMS(curbuf)[idx].sp_type =
  346.     (item == ITEM_START) ? SPTYPE_START :
  347.     (item == ITEM_SKIP) ? SPTYPE_SKIP : SPTYPE_END;
  348.     SYN_ITEMS(curbuf)[idx].sp_flags |= flags;
  349.     SYN_ITEMS(curbuf)[idx].sp_syn_id = syn_id;
  350.     SYN_ITEMS(curbuf)[idx].sp_syn_inc_lvl = current_syn_inc_lvl;
  351.     SYN_ITEMS(curbuf)[idx].sp_syn_match_id =
  352. ppp->pp_matchgroup_id;
  353.     if (item == ITEM_START)
  354.     {
  355. SYN_ITEMS(curbuf)[idx].sp_cont_list = cont_list;
  356. SYN_ITEMS(curbuf)[idx].sp_next_list = next_list;
  357.     }
  358.     ++curbuf->b_syn_patterns.ga_len;
  359.     --curbuf->b_syn_patterns.ga_room;
  360.     ++idx;
  361. }
  362.     }
  363.     redraw_curbuf_later(NOT_VALID);
  364.     success = TRUE;     /* don't free the progs and patterns now */
  365. }
  366.     }
  367.     /*
  368.      * Free the allocated memory.
  369.      */
  370.     for (item = ITEM_START; item <= ITEM_END; ++item)
  371. for (ppp = pat_ptrs[item]; ppp != NULL; ppp = ppp_next)
  372. {
  373.     if (!success)
  374.     {
  375. vim_free(ppp->pp_synp->sp_prog);
  376. vim_free(ppp->pp_synp->sp_pattern);
  377.     }
  378.     vim_free(ppp->pp_synp);
  379.     ppp_next = ppp->pp_next;
  380.     vim_free(ppp);
  381. }
  382.     if (!success)
  383.     {
  384. vim_free(cont_list);
  385. vim_free(next_list);
  386. if (not_enough)
  387.     EMSG2("Not enough arguments: syntax region %s", arg);
  388. else if (illegal || rest == NULL)
  389.     EMSG2(e_invarg2, arg);
  390.     }
  391. }
  392. /*
  393.  * A simple syntax group ID comparison function suitable for use in qsort()
  394.  */
  395.     static int
  396. #ifdef __BORLANDC__
  397. _RTLENTRYF
  398. #endif
  399. syn_compare_stub(v1, v2)
  400.     const void *v1;
  401.     const void *v2;
  402. {
  403.     const short *s1 = v1;
  404.     const short *s2 = v2;
  405.     return (*s1 > *s2 ? 1 : *s1 < *s2 ? -1 : 0);
  406. }
  407. /*
  408.  * Combines lists of syntax clusters.
  409.  * *clstr1 and *clstr2 must both be allocated memory; they will be consumed.
  410.  */
  411.     static void
  412. syn_combine_list(clstr1, clstr2, list_op)
  413.     short **clstr1;
  414.     short **clstr2;
  415.     int list_op;
  416. {
  417.     int count1 = 0;
  418.     int count2 = 0;
  419.     short *g1;
  420.     short *g2;
  421.     short *clstr = NULL;
  422.     int count;
  423.     int round;
  424.     /*
  425.      * Handle degenerate cases.
  426.      */
  427.     if (*clstr2 == NULL)
  428. return;
  429.     if (*clstr1 == NULL || list_op == CLUSTER_REPLACE)
  430.     {
  431. if (list_op == CLUSTER_REPLACE)
  432.     vim_free(*clstr1);
  433. if (list_op == CLUSTER_REPLACE || list_op == CLUSTER_ADD)
  434.     *clstr1 = *clstr2;
  435. else
  436.     vim_free(*clstr2);
  437. return;
  438.     }
  439.     for (g1 = *clstr1; *g1; g1++)
  440. ++count1;
  441.     for (g2 = *clstr2; *g2; g2++)
  442. ++count2;
  443.     /*
  444.      * For speed purposes, sort both lists.
  445.      */
  446.     qsort(*clstr1, (size_t)count1, sizeof(short), syn_compare_stub);
  447.     qsort(*clstr2, (size_t)count2, sizeof(short), syn_compare_stub);
  448.     /*
  449.      * We proceed in two passes; in round 1, we count the elements to place
  450.      * in the new list, and in round 2, we allocate and populate the new
  451.      * list.  For speed, we use a mergesort-like method, adding the smaller
  452.      * of the current elements in each list to the new list.
  453.      */
  454.     for (round = 1; round <= 2; round++)
  455.     {
  456. g1 = *clstr1;
  457. g2 = *clstr2;
  458. count = 0;
  459. /*
  460.  * First, loop through the lists until one of them is empty.
  461.  */
  462. while (*g1 && *g2)
  463. {
  464.     /*
  465.      * We always want to add from the first list.
  466.      */
  467.     if (*g1 < *g2)
  468.     {
  469. if (round == 2)
  470.     clstr[count] = *g1;
  471. count++;
  472. g1++;
  473. continue;
  474.     }
  475.     /*
  476.      * We only want to add from the second list if we're adding the
  477.      * lists.
  478.      */
  479.     if (list_op == CLUSTER_ADD)
  480.     {
  481. if (round == 2)
  482.     clstr[count] = *g2;
  483. count++;
  484.     }
  485.     if (*g1 == *g2)
  486. g1++;
  487.     g2++;
  488. }
  489. /*
  490.  * Now add the leftovers from whichever list didn't get finished
  491.  * first.  As before, we only want to add from the second list if
  492.  * we're adding the lists.
  493.  */
  494. for (; *g1; g1++, count++)
  495.     if (round == 2)
  496. clstr[count] = *g1;
  497. if (list_op == CLUSTER_ADD)
  498.     for (; *g2; g2++, count++)
  499. if (round == 2)
  500.     clstr[count] = *g2;
  501. if (round == 1)
  502. {
  503.     /*
  504.      * If the group ended up empty, we don't need to allocate any
  505.      * space for it.
  506.      */
  507.     if (count == 0)
  508.     {
  509. clstr = NULL;
  510. break;
  511.     }
  512.     clstr = (short *)alloc((unsigned)((count + 1) * sizeof(short)));
  513.     if (clstr == NULL)
  514. break;
  515.     clstr[count] = 0;
  516. }
  517.     }
  518.     /*
  519.      * Finally, put the new list in place.
  520.      */
  521.     vim_free(*clstr1);
  522.     vim_free(*clstr2);
  523.     *clstr1 = clstr;
  524. }
  525. /*
  526.  * Lookup a syntax cluster name and return it's ID.
  527.  * If it is not found, 0 is returned.
  528.  */
  529.     static int
  530. syn_scl_name2id(name)
  531.     char_u *name;
  532. {
  533.     int i;
  534.     char_u *name_u;
  535.     /* Avoid using stricmp() too much, it's slow on some systems */
  536.     name_u = vim_strsave_up(name);
  537.     if (name_u == NULL)
  538. return 0;
  539.     for (i = curbuf->b_syn_clusters.ga_len; --i >= 0; )
  540. if (SYN_CLSTR(curbuf)[i].scl_name_u != NULL
  541. && STRCMP(name_u, SYN_CLSTR(curbuf)[i].scl_name_u) == 0)
  542.     break;
  543.     vim_free(name_u);
  544.     return (i < 0 ? 0 : i + CLUSTER_ID_MIN);
  545. }
  546. /*
  547.  * Like syn_scl_name2id(), but take a pointer + length argument.
  548.  */
  549.     static int
  550. syn_scl_namen2id(linep, len)
  551.     char_u  *linep;
  552.     int     len;
  553. {
  554.     char_u  *name;
  555.     int     id = 0;
  556.     name = vim_strnsave(linep, len);
  557.     if (name != NULL)
  558.     {
  559. id = syn_scl_name2id(name);
  560. vim_free(name);
  561.     }
  562.     return id;
  563. }
  564. /*
  565.  * Find syntax cluster name in the table and return it's ID.
  566.  * The argument is a pointer to the name and the length of the name.
  567.  * If it doesn't exist yet, a new entry is created.
  568.  * Return 0 for failure.
  569.  */
  570.     static int
  571. syn_check_cluster(pp, len)
  572.     char_u *pp;
  573.     int len;
  574. {
  575.     int id;
  576.     char_u *name;
  577.     name = vim_strnsave(pp, len);
  578.     if (name == NULL)
  579. return 0;
  580.     id = syn_scl_name2id(name);
  581.     if (id == 0) /* doesn't exist yet */
  582. id = syn_add_cluster(name);
  583.     else
  584. vim_free(name);
  585.     return id;
  586. }
  587. /*
  588.  * Add new syntax cluster and return it's ID.
  589.  * "name" must be an allocated string, it will be consumed.
  590.  * Return 0 for failure.
  591.  */
  592.     static int
  593. syn_add_cluster(name)
  594.     char_u *name;
  595. {
  596.     int len;
  597.     /*
  598.      * First call for this growarray: init growing array.
  599.      */
  600.     if (curbuf->b_syn_clusters.ga_data == NULL)
  601.     {
  602. curbuf->b_syn_clusters.ga_itemsize = sizeof(struct syn_cluster);
  603. curbuf->b_syn_clusters.ga_growsize = 10;
  604.     }
  605.     /*
  606.      * Make room for at least one other cluster entry.
  607.      */
  608.     if (ga_grow(&curbuf->b_syn_clusters, 1) == FAIL)
  609.     {
  610. vim_free(name);
  611. return 0;
  612.     }
  613.     len = curbuf->b_syn_clusters.ga_len;
  614.     vim_memset(&(SYN_CLSTR(curbuf)[len]), 0, sizeof(struct syn_cluster));
  615.     SYN_CLSTR(curbuf)[len].scl_name = name;
  616.     SYN_CLSTR(curbuf)[len].scl_name_u = vim_strsave_up(name);
  617.     SYN_CLSTR(curbuf)[len].scl_list = NULL;
  618.     ++curbuf->b_syn_clusters.ga_len;
  619.     --curbuf->b_syn_clusters.ga_room;
  620.     return len + CLUSTER_ID_MIN;
  621. }
  622. /*
  623.  * Handle ":syntax cluster {cluster-name} [contains={groupname},..]
  624.  * [add={groupname},..] [remove={groupname},..]".
  625.  */
  626. /* ARGSUSED */
  627.     static void
  628. syn_cmd_cluster(eap, syncing)
  629.     EXARG *eap;
  630.     int syncing;     /* not used */
  631. {
  632.     char_u *arg = eap->arg;
  633.     char_u *group_name_end;
  634.     char_u *rest;
  635.     int scl_id;
  636.     short *clstr_list;
  637.     int got_clstr = FALSE;
  638.     int opt_len;
  639.     int list_op;
  640.     eap->nextcmd = find_nextcmd(arg);
  641.     if (eap->skip)
  642. return;
  643.     rest = get_group_name(arg, &group_name_end);
  644.     if (rest != NULL)
  645.     {
  646. scl_id = syn_check_cluster(arg, (int)(group_name_end - arg))
  647.     - CLUSTER_ID_MIN;
  648. for (;;)
  649. {
  650.     if (STRNICMP(rest, "add", 3) == 0
  651.     && (vim_iswhite(rest[3]) || rest[3] == '='))
  652.     {
  653. opt_len = 3;
  654. list_op = CLUSTER_ADD;
  655.     }
  656.     else if (STRNICMP(rest, "remove", 6) == 0
  657.     && (vim_iswhite(rest[6]) || rest[6] == '='))
  658.     {
  659. opt_len = 6;
  660. list_op = CLUSTER_SUBTRACT;
  661.     }
  662.     else if (STRNICMP(rest, "contains", 8) == 0
  663. && (vim_iswhite(rest[8]) || rest[8] == '='))
  664.     {
  665. opt_len = 8;
  666. list_op = CLUSTER_REPLACE;
  667.     }
  668.     else
  669. break;
  670.     clstr_list = NULL;
  671.     if (get_id_list(&rest, opt_len, &clstr_list) == FAIL)
  672.     {
  673. EMSG2(e_invarg2, rest);
  674. break;
  675.     }
  676.     syn_combine_list(&SYN_CLSTR(curbuf)[scl_id].scl_list,
  677.      &clstr_list, list_op);
  678.     got_clstr = TRUE;
  679. }
  680. if (got_clstr)
  681.     redraw_curbuf_later(NOT_VALID);
  682.     }
  683.     if (!got_clstr)
  684. EMSG("No cluster specified");
  685.     if (rest == NULL || !ends_excmd(*rest))
  686. EMSG2(e_invarg2, arg);
  687. }
  688. /*
  689.  * On first call for current buffer: Init growing array.
  690.  */
  691.     static void
  692. init_syn_patterns()
  693. {
  694.     curbuf->b_syn_patterns.ga_itemsize = sizeof(struct syn_pattern);
  695.     curbuf->b_syn_patterns.ga_growsize = 10;
  696. }
  697. /*
  698.  * Get one pattern for a ":syntax match" or ":syntax region" command.
  699.  * Stores the pattern and program in a struct syn_pattern.
  700.  * Returns a pointer to the next argument, or NULL in case of an error.
  701.  */
  702.     static char_u *
  703. get_syn_pattern(arg, ci)
  704.     char_u *arg;
  705.     struct syn_pattern *ci;
  706. {
  707.     char_u *end;
  708.     int *p;
  709.     int idx;
  710.     char_u *cpo_save;
  711.     /* need at least three chars */
  712.     if (arg == NULL || arg[1] == NUL || arg[2] == NUL)
  713. return NULL;
  714.     end = skip_regexp(arg + 1, *arg, TRUE);
  715.     if (*end != *arg)     /* end delimiter not found */
  716.     {
  717. EMSG2("Pattern delimiter not found: %s", arg);
  718. return NULL;
  719.     }
  720.     /* store the pattern and compiled regexp program */
  721.     if ((ci->sp_pattern = vim_strnsave(arg + 1, (int)(end - arg - 1))) == NULL)
  722. return NULL;
  723.     /* Make 'cpoptions' empty, to avoid the 'l' flag */
  724.     cpo_save = p_cpo;
  725.     p_cpo = (char_u *)"";
  726.     ci->sp_prog = vim_regcomp(ci->sp_pattern, TRUE);
  727.     p_cpo = cpo_save;
  728.     if (ci->sp_prog == NULL)
  729. return NULL;
  730.     ci->sp_ic = curbuf->b_syn_ic;
  731.     /*
  732.      * Check for a match, highlight or region offset.
  733.      */
  734.     ++end;
  735.     do
  736.     {
  737. for (idx = SPO_COUNT; --idx >= 0; )
  738.     if (STRNCMP(end, spo_name_tab[idx], 3) == 0)
  739. break;
  740. if (idx >= 0)
  741. {
  742.     p = &(ci->sp_offsets[idx]);
  743.     if (idx != SPO_LC_OFF)
  744. switch (end[3])
  745. {
  746.     case 's':   break;
  747.     case 'b':   break;
  748.     case 'e':   idx += SPO_COUNT; break;
  749.     default:    idx = -1; break;
  750. }
  751.     if (idx >= 0)
  752.     {
  753. ci->sp_off_flags |= (1 << idx);
  754. if (idx == SPO_LC_OFF)     /* lc=99 */
  755. {
  756.     end += 3;
  757.     *p = getdigits(&end);
  758.     /* "lc=" offset automatically sets "ms=" offset */
  759.     if (!(ci->sp_off_flags & (1 << SPO_MS_OFF)))
  760.     {
  761. ci->sp_off_flags |= (1 << SPO_MS_OFF);
  762. ci->sp_offsets[SPO_MS_OFF] = *p;
  763.     }
  764. }
  765. else     /* yy=x+99 */
  766. {
  767.     end += 4;
  768.     if (*end == '+')
  769.     {
  770. ++end;
  771. *p = getdigits(&end); /* positive offset */
  772.     }
  773.     else if (*end == '-')
  774.     {
  775. ++end;
  776. *p = -getdigits(&end); /* negative offset */
  777.     }
  778. }
  779. if (*end != ',')
  780.     break;
  781. ++end;
  782.     }
  783. }
  784.     } while (idx >= 0);
  785.     if (!ends_excmd(*end) && !vim_iswhite(*end))
  786.     {
  787. EMSG2("Garbage after pattern: %s", arg);
  788. return NULL;
  789.     }
  790.     return skipwhite(end);
  791. }
  792. /*
  793.  * Handle ":syntax sync .." command.
  794.  */
  795. /* ARGSUSED */
  796.     static void
  797. syn_cmd_sync(eap, syncing)
  798.     EXARG *eap;
  799.     int syncing;     /* not used */
  800. {
  801.     char_u *arg_start = eap->arg;
  802.     char_u *arg_end;
  803.     char_u *key = NULL;
  804.     char_u *next_arg;
  805.     int illegal = FALSE;
  806.     int finished = FALSE;
  807.     long n;
  808.     char_u *cpo_save;
  809.     if (ends_excmd(*arg_start))
  810.     {
  811. syn_cmd_list(eap, TRUE);
  812. return;
  813.     }
  814.     while (!ends_excmd(*arg_start))
  815.     {
  816. arg_end = skiptowhite(arg_start);
  817. next_arg = skipwhite(arg_end);
  818. vim_free(key);
  819. key = vim_strnsave_up(arg_start, (int)(arg_end - arg_start));
  820. if (STRCMP(key, "CCOMMENT") == 0)
  821. {
  822.     if (!eap->skip)
  823. curbuf->b_syn_sync_flags |= SF_CCOMMENT;
  824.     if (!ends_excmd(*next_arg))
  825.     {
  826. arg_end = skiptowhite(next_arg);
  827. if (!eap->skip)
  828.     curbuf->b_syn_sync_id = syn_check_group(next_arg,
  829.    (int)(arg_end - next_arg));
  830. next_arg = skipwhite(arg_end);
  831.     }
  832.     else if (!eap->skip)
  833. curbuf->b_syn_sync_id = syn_name2id((char_u *)"Comment");
  834. }
  835. else if (  STRNCMP(key, "LINES", 5) == 0
  836. || STRNCMP(key, "MINLINES", 8) == 0
  837. || STRNCMP(key, "MAXLINES", 8) == 0)
  838. {
  839.     if (key[0] == 'L')
  840. arg_end = key + 6;
  841.     else
  842. arg_end = key + 9;
  843.     if (arg_end[-1] != '=' || !isdigit(*arg_end))
  844.     {
  845. illegal = TRUE;
  846. break;
  847.     }
  848.     n = getdigits(&arg_end);
  849.     if (!eap->skip)
  850.     {
  851. if (key[1] == 'A')
  852.     curbuf->b_syn_sync_maxlines = n;
  853. else
  854.     curbuf->b_syn_sync_minlines = n;
  855.     }
  856. }
  857. else if (STRCMP(key, "LINECONT") == 0)
  858. {
  859.     if (curbuf->b_syn_linecont_pat != NULL)
  860.     {
  861. EMSG("syntax sync: line continuations pattern specified twice");
  862. finished = TRUE;
  863. break;
  864.     }
  865.     arg_end = skip_regexp(next_arg + 1, *next_arg, TRUE);
  866.     if (*arg_end != *next_arg)     /* end delimiter not found */
  867.     {
  868. illegal = TRUE;
  869. break;
  870.     }
  871.     if (!eap->skip)
  872.     {
  873. /* store the pattern and compiled regexp program */
  874. if ((curbuf->b_syn_linecont_pat = vim_strnsave(next_arg + 1,
  875.       (int)(arg_end - next_arg - 1))) == NULL)
  876. {
  877.     finished = TRUE;
  878.     break;
  879. }
  880. curbuf->b_syn_linecont_ic = curbuf->b_syn_ic;
  881. /* Make 'cpoptions' empty, to avoid the 'l' flag */
  882. cpo_save = p_cpo;
  883. p_cpo = (char_u *)"";
  884. curbuf->b_syn_linecont_prog =
  885. vim_regcomp(curbuf->b_syn_linecont_pat, TRUE);
  886. p_cpo = cpo_save;
  887. if (curbuf->b_syn_linecont_prog == NULL)
  888. {
  889.     vim_free(curbuf->b_syn_linecont_pat);
  890.     curbuf->b_syn_linecont_pat = NULL;
  891.     finished = TRUE;
  892.     break;
  893. }
  894.     }
  895.     next_arg = skipwhite(arg_end + 1);
  896. }
  897. else
  898. {
  899.     eap->arg = next_arg;
  900.     if (STRCMP(key, "MATCH") == 0)
  901. syn_cmd_match(eap, TRUE);
  902.     else if (STRCMP(key, "REGION") == 0)
  903. syn_cmd_region(eap, TRUE);
  904.     else if (STRCMP(key, "CLEAR") == 0)
  905. syn_cmd_clear(eap, TRUE);
  906.     else
  907. illegal = TRUE;
  908.     finished = TRUE;
  909.     break;
  910. }
  911. arg_start = next_arg;
  912.     }
  913.     vim_free(key);
  914.     if (illegal)
  915. EMSG2("Illegal arguments: %s", arg_start);
  916.     else if (!finished)
  917.     {
  918. eap->nextcmd = check_nextcmd(arg_start);
  919. redraw_curbuf_later(NOT_VALID);
  920.     }
  921. }
  922. /*
  923.  * Convert a line of highlight group names into a list of group ID numbers.
  924.  * "arg" should point to the "contains" or "nextgroup" keyword.
  925.  * "arg" is advanced to after the last group name.
  926.  * Careful: the argument is modified (NULs added).
  927.  * returns FAIL for some error, OK for success.
  928.  */
  929.     static int
  930. get_id_list(arg, keylen, list)
  931.     char_u **arg;
  932.     int keylen; /* length of keyword */
  933.     short **list; /* where to store the resulting list, if not
  934.    NULL, the list is silently skipped! */
  935. {
  936.     char_u *p;
  937.     char_u *end;
  938.     int round;
  939.     int count;
  940.     short *retval = NULL;
  941.     char_u *name;
  942.     vim_regexp *prog;
  943.     int id;
  944.     int i;
  945.     int failed = FALSE;
  946.     /*
  947.      * We parse the list twice:
  948.      * round == 1: count the number of items, allocate the array.
  949.      * round == 2: fill the array with the items.
  950.      */
  951.     for (round = 1; round <= 2; ++round)
  952.     {
  953. /*
  954.  * skip "contains"
  955.  */
  956. p = skipwhite(*arg + keylen);
  957. if (*p != '=')
  958. {
  959.     EMSG2("Missing equal sign: %s", *arg);
  960.     break;
  961. }
  962. p = skipwhite(p + 1);
  963. if (ends_excmd(*p))
  964. {
  965.     EMSG2("Empty argument: %s", *arg);
  966.     break;
  967. }
  968. /*
  969.  * parse the arguments after "contains"
  970.  */
  971. count = 0;
  972. while (!ends_excmd(*p))
  973. {
  974.     for (end = p; *end && !vim_iswhite(*end) && *end != ','; ++end)
  975. ;
  976.     name = alloc((int)(end - p + 3));     /* leave room for "^$" */
  977.     if (name == NULL)
  978.     {
  979. failed = TRUE;
  980. break;
  981.     }
  982.     STRNCPY(name + 1, p, end - p);
  983.     name[end - p + 1] = NUL;
  984.     if (       STRCMP(name + 1, "ALLBUT") == 0
  985.     || STRCMP(name + 1, "ALL") == 0)
  986.     {
  987. if (TO_UPPER(**arg) != 'C')
  988. {
  989.     EMSG2("%s not allowed here", name + 1);
  990.     failed = TRUE;
  991.     vim_free(name);
  992.     break;
  993. }
  994. if (count != 0)
  995. {
  996.     EMSG2("%s must be first in contains list", name + 1);
  997.     failed = TRUE;
  998.     vim_free(name);
  999.     break;
  1000. }
  1001. id = CONTAINS_ALLBUT + current_syn_inc_lvl;
  1002.     }
  1003.     else if (name[1] == '@')
  1004.     {
  1005. id = syn_check_cluster(name + 2, (int)(end - p - 1));
  1006.     }
  1007.     else
  1008.     {
  1009. /*
  1010.  * Handle full group name.
  1011.  */
  1012. if (vim_strpbrk(name + 1, (char_u *)"\.*^$~[") == NULL)
  1013.     id = syn_check_group(name + 1, (int)(end - p));
  1014. else
  1015. {
  1016.     /*
  1017.      * Handle match of regexp with group names.
  1018.      */
  1019.     *name = '^';
  1020.     STRCAT(name, "$");
  1021.     prog = vim_regcomp(name, TRUE);
  1022.     if (prog == NULL)
  1023.     {
  1024. failed = TRUE;
  1025. vim_free(name);
  1026. break;
  1027.     }
  1028.     reg_ic = TRUE;
  1029.     id = 0;
  1030.     for (i = highlight_ga.ga_len; --i >= 0; )
  1031.     {
  1032. if (vim_regexec(prog, HL_TABLE()[i].sg_name, TRUE))
  1033. {
  1034.     if (round == 2)
  1035. retval[count] = i + 1;
  1036.     ++count;
  1037.     id = -1;     /* remember that we found one */
  1038. }
  1039.     }
  1040.     vim_free(prog);
  1041. }
  1042.     }
  1043.     vim_free(name);
  1044.     if (id == 0)
  1045.     {
  1046. EMSG2("Unknown group name: %s", p);
  1047. failed = TRUE;
  1048. break;
  1049.     }
  1050.     if (id > 0)
  1051.     {
  1052. if (round == 2)
  1053.     retval[count] = id;
  1054. ++count;
  1055.     }
  1056.     p = skipwhite(end);
  1057.     if (*p != ',')
  1058. break;
  1059.     p = skipwhite(p + 1); /* skip comma in between arguments */
  1060. }
  1061. if (failed)
  1062.     break;
  1063. if (round == 1)
  1064. {
  1065.     retval = (short *)alloc((unsigned)((count + 1) * sizeof(short)));
  1066.     if (retval == NULL)
  1067. break;
  1068.     retval[count] = 0;     /* zero means end of the list */
  1069. }
  1070.     }
  1071.     *arg = p;
  1072.     if (failed || retval == NULL)
  1073.     {
  1074. vim_free(retval);
  1075. return FAIL;
  1076.     }
  1077.     if (*list == NULL)
  1078. *list = retval;
  1079.     else
  1080. vim_free(retval); /* list already found, don't overwrite it */
  1081.     return OK;
  1082. }
  1083. /*
  1084.  * Make a copy of an ID list.
  1085.  */
  1086.     static short *
  1087. copy_id_list(list)
  1088.     short   *list;
  1089. {
  1090.     int     len;
  1091.     int     count;
  1092.     short   *retval;
  1093.     if (list == NULL)
  1094. return NULL;
  1095.     for (count = 0; list[count]; ++count)
  1096. ;
  1097.     len = (count + 1) * sizeof(short);
  1098.     retval = (short *)alloc((unsigned)len);
  1099.     if (retval != NULL)
  1100. mch_memmove(retval, list, (size_t)len);
  1101.     return retval;
  1102. }
  1103. /*
  1104.  * Check if "id" is in the "contains" or "nextgroup" list of pattern "idx".
  1105.  */
  1106.     static int
  1107. in_id_list(list, id, inclvl, contained)
  1108.     short *list; /* id list */
  1109.     int id; /* group id */
  1110.     int inclvl; /* ":syn include" level of group id */
  1111.     int contained; /* group id is contained */
  1112. {
  1113.     int retval;
  1114.     short scl_id;
  1115.     short *scl_list;
  1116.     /*
  1117.      * If list is ID_LIST_ALL, we are in a transparent item that isn't
  1118.      * inside anything.  Only allow not-contained groups.
  1119.      */
  1120.     if (list == ID_LIST_ALL)
  1121. return !contained;
  1122.     /*
  1123.      * If the first item is "ALLBUT", return TRUE if id is NOT in the contains
  1124.      * list.  We also require that id is at the same ":syn include" level
  1125.      * as the list.
  1126.      */
  1127.     if (*list >= CONTAINS_ALLBUT && *list < CLUSTER_ID_MIN)
  1128.     {
  1129. if (*list - CONTAINS_ALLBUT != inclvl)
  1130.     return FALSE;
  1131. ++list;
  1132. retval = FALSE;
  1133.     }
  1134.     else
  1135. retval = TRUE;
  1136.     /*
  1137.      * Return "retval" if id is in the contains list.
  1138.      */
  1139.     for (; *list; ++list)
  1140.     {
  1141. if (*list == id)
  1142.     return retval;
  1143. scl_id = *list - CLUSTER_ID_MIN;
  1144. if (scl_id >= 0)
  1145. {
  1146.     scl_list = SYN_CLSTR(syn_buf)[scl_id].scl_list;
  1147.     if (scl_list != NULL && in_id_list(scl_list, id, inclvl, contained))
  1148. return retval;
  1149. }
  1150.     }
  1151.     return !retval;
  1152. }
  1153. struct subcommand
  1154. {
  1155.     char    *name; /* subcommand name */
  1156.     void    (*func)__ARGS((EXARG *, int)); /* function to call */
  1157. };
  1158. static struct subcommand subcommands[] =
  1159. {
  1160.     {"case", syn_cmd_case},
  1161.     {"clear", syn_cmd_clear},
  1162.     {"cluster", syn_cmd_cluster},
  1163.     {"include", syn_cmd_include},
  1164.     {"keyword", syn_cmd_keyword},
  1165.     {"list", syn_cmd_list},
  1166.     {"match", syn_cmd_match},
  1167.     {"on", syn_cmd_on},
  1168.     {"off", syn_cmd_off},
  1169.     {"region", syn_cmd_region},
  1170.     {"sync", syn_cmd_sync},
  1171.     {"", syn_cmd_list},
  1172.     {NULL, NULL}
  1173. };
  1174. /*
  1175.  * Handle the ":syntax" command.
  1176.  * This searches the subcommands[] table for the subcommand name, and calls a
  1177.  * syntax_subcommand() function to do the rest.
  1178.  */
  1179.     void
  1180. do_syntax(eap, cmdlinep)
  1181.     EXARG *eap;
  1182.     char_u **cmdlinep;
  1183. {
  1184.     char_u *arg = eap->arg;
  1185.     char_u *subcmd_end;
  1186.     char_u *subcmd_name;
  1187.     int i;
  1188.     syn_cmdlinep = cmdlinep;
  1189.     /* isolate subcommand name */
  1190.     for (subcmd_end = arg; isalpha(*subcmd_end); ++subcmd_end)
  1191. ;
  1192.     subcmd_name = vim_strnsave(arg, (int)(subcmd_end - arg));
  1193.     if (subcmd_name != NULL)
  1194.     {
  1195. if (eap->skip) /* skip error messages for all subcommands */
  1196.     ++emsg_off;
  1197. for (i = 0; ; ++i)
  1198. {
  1199.     if (subcommands[i].name == NULL)
  1200.     {
  1201. EMSG2("Invalid :syntax subcommand: %s", subcmd_name);
  1202. break;
  1203.     }
  1204.     if (STRCMP(subcmd_name, (char_u *)subcommands[i].name) == 0)
  1205.     {
  1206. eap->arg = skipwhite(subcmd_end);
  1207. (subcommands[i].func)(eap, FALSE);
  1208. break;
  1209.     }
  1210. }
  1211. vim_free(subcmd_name);
  1212. if (eap->skip)
  1213.     --emsg_off;
  1214.     }
  1215. }
  1216.     int
  1217. syntax_present(buf)
  1218.     BUF     *buf;
  1219. {
  1220.     return (buf->b_syn_patterns.ga_len != 0
  1221.     || buf->b_syn_clusters.ga_len != 0
  1222.     || curbuf->b_keywtab != NULL
  1223.     || curbuf->b_keywtab_ic != NULL);
  1224. }
  1225. static enum
  1226. {
  1227.     EXP_SUBCMD,     /* expand ":syn" sub-commands */
  1228.     EXP_CASE     /* expand ":syn case" arguments */
  1229. } expand_what;
  1230. /*
  1231.  * Handle command line completion for :syntax command.
  1232.  */
  1233.     void
  1234. set_context_in_syntax_cmd(arg)
  1235.     char_u *arg;
  1236. {
  1237.     char_u *p;
  1238.     /* Default: expand subcommands */
  1239.     expand_context = EXPAND_SYNTAX;
  1240.     expand_what = EXP_SUBCMD;
  1241.     expand_pattern = arg;
  1242.     include_link = FALSE;
  1243.     /* (part of) subcommand already typed */
  1244.     if (*arg != NUL)
  1245.     {
  1246. p = skiptowhite(arg);
  1247. if (*p != NUL)     /* past first word */
  1248. {
  1249.     expand_pattern = skipwhite(p);
  1250.     if (*skiptowhite(expand_pattern) != NUL)
  1251. expand_context = EXPAND_NOTHING;
  1252.     else if (STRNICMP(arg, "case", p - arg) == 0)
  1253. expand_what = EXP_CASE;
  1254.     else if (  STRNICMP(arg, "keyword", p - arg) == 0
  1255.     || STRNICMP(arg, "region", p - arg) == 0
  1256.     || STRNICMP(arg, "match", p - arg) == 0
  1257.     || STRNICMP(arg, "list", p - arg) == 0)
  1258. expand_context = EXPAND_HIGHLIGHT;
  1259.     else
  1260. expand_context = EXPAND_NOTHING;
  1261. }
  1262.     }
  1263. }
  1264. static char *(case_args[]) = {"match", "ignore", NULL};
  1265. /*
  1266.  * Function given to ExpandGeneric() to obtain the list syntax names for
  1267.  * expansion.
  1268.  */
  1269.     char_u *
  1270. get_syntax_name(idx)
  1271.     int     idx;
  1272. {
  1273.     if (expand_what == EXP_SUBCMD)
  1274. return (char_u *)subcommands[idx].name;
  1275.     return (char_u *)case_args[idx];
  1276. }
  1277. #ifdef WANT_EVAL
  1278. /*
  1279.  * Function called for expression evaluation: get syntax ID at file position.
  1280.  */
  1281.     int
  1282. syn_get_id(line, col, trans)
  1283.     long line;
  1284.     long col;
  1285.     int trans;     /* remove transparancy */
  1286. {
  1287.     if (curwin->w_buffer != syn_buf
  1288.    || col < (long)current_col || line != current_lnum)
  1289. syntax_start(curwin, line);
  1290.     (void)get_syntax_attr((colnr_t)col, ml_get((linenr_t)line));
  1291.     return (trans ? current_trans_id : current_id);
  1292. }
  1293. #endif
  1294. /*
  1295.  * Call vim_regexec() with the current buffer set to syn_buf.  Makes
  1296.  * vim_iswordc() work correctly.
  1297.  */
  1298.     static int
  1299. syn_regexec(prog, string, at_bol)
  1300.     vim_regexp *prog;
  1301.     char_u *string;
  1302.     int at_bol;
  1303. {
  1304.     int retval;
  1305.     BUF *save_curbuf;
  1306.     save_curbuf = curbuf;
  1307.     curbuf = syn_buf;
  1308.     retval = vim_regexec(prog, string, at_bol);
  1309.     curbuf = save_curbuf;
  1310.     return retval;
  1311. }
  1312. #endif /* SYNTAX_HL */
  1313. /**************************************
  1314.  *  Highlighting stuff       *
  1315.  **************************************/
  1316. /*
  1317.  * The default highlight groups.  Used in the 'highlight' and 'guicursor'
  1318.  * options default.  Depends on 'background' option.
  1319.  */
  1320. static char *(highlight_init_both[]) =
  1321.     {
  1322. #ifdef USE_GUI
  1323. "Cursor guibg=fg guifg=bg",
  1324. #endif
  1325. "ErrorMsg term=standout ctermbg=DarkRed ctermfg=White guibg=Red guifg=White",
  1326. "IncSearch term=reverse cterm=reverse gui=reverse",
  1327. "ModeMsg term=bold cterm=bold gui=bold",
  1328. "NonText term=bold ctermfg=Blue gui=bold guifg=Blue",
  1329. "StatusLine term=reverse,bold cterm=reverse,bold gui=reverse,bold",
  1330. "StatusLineNC term=reverse cterm=reverse gui=reverse",
  1331. "Visual term=reverse cterm=reverse gui=reverse guifg=Grey guibg=fg",
  1332. NULL
  1333.     };
  1334. static char *(highlight_init_light[]) =
  1335.     {
  1336. "Directory term=bold ctermfg=DarkBlue guifg=Blue",
  1337. "LineNr term=underline ctermfg=Brown guifg=Brown",
  1338. "MoreMsg term=bold ctermfg=DarkGreen gui=bold guifg=SeaGreen",
  1339. "Normal gui=NONE",
  1340. "Question term=standout ctermfg=DarkGreen gui=bold guifg=SeaGreen",
  1341. "Search term=reverse ctermbg=Yellow ctermfg=NONE guibg=Yellow guifg=NONE",
  1342. "SpecialKey term=bold ctermfg=DarkBlue guifg=Blue",
  1343. "Title term=bold ctermfg=DarkMagenta gui=bold guifg=Magenta",
  1344. "WarningMsg term=standout ctermfg=DarkRed guifg=Red",
  1345. NULL
  1346.     };
  1347. static char *(highlight_init_dark[]) =
  1348.     {
  1349. "Directory term=bold ctermfg=LightCyan guifg=Cyan",
  1350. "LineNr term=underline ctermfg=Yellow guifg=Yellow",
  1351. "MoreMsg term=bold ctermfg=LightGreen gui=bold guifg=SeaGreen",
  1352. "Normal gui=NONE",
  1353. "Question term=standout ctermfg=LightGreen gui=bold guifg=Green",
  1354. "Search term=reverse ctermbg=Yellow ctermfg=Black guibg=Yellow guifg=Black",
  1355. "SpecialKey term=bold ctermfg=LightBlue guifg=Cyan",
  1356. "Title term=bold ctermfg=LightMagenta gui=bold guifg=Magenta",
  1357. "WarningMsg term=standout ctermfg=LightRed guifg=Red",
  1358. NULL
  1359.     };
  1360.     void
  1361. init_highlight(both)
  1362.     int both;     /* include groups where 'bg' doesn't matter */
  1363. {
  1364.     int i;
  1365.     char **pp;
  1366.     if (both)
  1367.     {
  1368. pp = highlight_init_both;
  1369. for (i = 0; pp[i] != NULL; ++i)
  1370.     do_highlight((char_u *)pp[i], FALSE, TRUE);
  1371.     }
  1372.     if (TO_LOWER(*p_bg) == 'l')
  1373. pp = highlight_init_light;
  1374.     else
  1375. pp = highlight_init_dark;
  1376.     for (i = 0; pp[i] != NULL; ++i)
  1377. do_highlight((char_u *)pp[i], FALSE, TRUE);
  1378. }
  1379. /*
  1380.  * Handle the ":highlight .." command.
  1381.  */
  1382.     void
  1383. do_highlight(line, forceit, init)
  1384.     char_u *line;
  1385.     int forceit;
  1386.     int init;     /* TRUE when called for initializing */
  1387. {
  1388.     char_u *name_end;
  1389.     char_u *p;
  1390.     char_u *linep;
  1391.     char_u *key_start;
  1392.     char_u *arg_start;
  1393.     char_u *key = NULL, *arg = NULL;
  1394.     int i;
  1395.     int off;
  1396.     int len;
  1397.     int attr;
  1398.     int id;
  1399.     int idx;
  1400.     int doclear = FALSE;
  1401.     int dolink = FALSE;
  1402.     int error = FALSE;
  1403.     int color;
  1404.     int is_normal_group = FALSE; /* "Normal" group */
  1405. #ifdef USE_GUI_X11
  1406.     int is_menu_group = FALSE; /* "Menu" group */
  1407.     int is_scrollbar_group = FALSE; /* "Scrollbar" group */
  1408. #endif
  1409.     /*
  1410.      * If no argument, list current highlighting.
  1411.      */
  1412.     if (ends_excmd(*line))
  1413.     {
  1414. for (i = 1; i <= highlight_ga.ga_len && !got_int; ++i)
  1415.     /* TODO: only call when the group has attributes set */
  1416.     highlight_list_one(i);
  1417. return;
  1418.     }
  1419.     /*
  1420.      * Isolate the name.
  1421.      */
  1422.     name_end = skiptowhite(line);
  1423.     linep = skipwhite(name_end);
  1424.     if (STRNCMP(line, "clear", name_end - line) == 0)
  1425. doclear = TRUE;
  1426.     if (STRNCMP(line, "link", name_end - line) == 0)
  1427. dolink = TRUE;
  1428.     /*
  1429.      * ":highlight {group-name}": list highlighting for one group.
  1430.      */
  1431.     if (!doclear && !dolink && ends_excmd(*linep))
  1432.     {
  1433. id = syn_namen2id(line, (int)(name_end - line));
  1434. if (id == 0)
  1435.     EMSG2("highlight group not found: %s", line);
  1436. else
  1437.     highlight_list_one(id);
  1438. return;
  1439.     }
  1440.     /*
  1441.      * Handle ":highlight link {from} {to}" command.
  1442.      */
  1443.     if (dolink)
  1444.     {
  1445. char_u     *from_start = linep;
  1446. char_u     *from_end;
  1447. char_u     *to_start;
  1448. char_u     *to_end;
  1449. int     from_id;
  1450. int     to_id;
  1451. from_end = skiptowhite(from_start);
  1452. to_start = skipwhite(from_end);
  1453. to_end  = skiptowhite(to_start);
  1454. if (ends_excmd(*from_start) || ends_excmd(*to_start))
  1455. {
  1456.     EMSG2("Not enough arguments: ":highlight link %s"", from_start);
  1457.     return;
  1458. }
  1459. if (!ends_excmd(*skipwhite(to_end)))
  1460. {
  1461.     EMSG2("Too many arguments: ":highlight link %s"", from_start);
  1462.     return;
  1463. }
  1464. from_id = syn_check_group(from_start, (int)(from_end - from_start));
  1465. if (STRNCMP(to_start, "NONE", 4) == 0)
  1466.     to_id = 0;
  1467. else
  1468.     to_id = syn_check_group(to_start, (int)(to_end - to_start));
  1469. if (from_id > 0 && (!init || HL_TABLE()[from_id - 1].sg_set == 0))
  1470. {
  1471.     /*
  1472.      * Don't allow a link when there already is some highlighting
  1473.      * for the group, unless '!' is used
  1474.      */
  1475.     if (to_id > 0 && !forceit && !init
  1476.     &&   (HL_TABLE()[from_id - 1].sg_term_attr != 0
  1477. || HL_TABLE()[from_id - 1].sg_cterm_attr != 0
  1478. #ifdef USE_GUI
  1479. || HL_TABLE()[from_id - 1].sg_gui_attr != 0
  1480. #endif
  1481.        ))
  1482.     {
  1483. if (sourcing_name == NULL)
  1484.     EMSG("group has settings, highlight link ignored");
  1485.     }
  1486.     else
  1487.     {
  1488. if (!init)
  1489.     HL_TABLE()[from_id - 1].sg_set |= SG_LINK;
  1490. HL_TABLE()[from_id - 1].sg_link = to_id;
  1491.     }
  1492. }
  1493. redraw_curbuf_later(NOT_VALID);
  1494. return;
  1495.     }
  1496.     /*
  1497.      * Handle ":highlight clear {group}" command.
  1498.      */
  1499.     if (doclear)
  1500.     {
  1501. line = linep;
  1502. if (ends_excmd(*line))
  1503. {
  1504.     EMSG("Cannot clear all highlight groups");
  1505.     return;
  1506. }
  1507. name_end = skiptowhite(line);
  1508. linep = skipwhite(name_end);
  1509.     }
  1510.     /*
  1511.      * Find the group name in the table.  If it does not exist yet, add it.
  1512.      */
  1513.     id = syn_check_group(line, (int)(name_end - line));
  1514.     if (id == 0) /* failed (out of memory) */
  1515. return;
  1516.     idx = id - 1; /* index is ID minus one */
  1517.     if (STRCMP(HL_TABLE()[idx].sg_name_u, "NORMAL") == 0)
  1518. is_normal_group = TRUE;
  1519. #ifdef USE_GUI_X11
  1520.     else if (STRCMP(HL_TABLE()[idx].sg_name_u, "MENU") == 0)
  1521. is_menu_group = TRUE;
  1522.     else if (STRCMP(HL_TABLE()[idx].sg_name_u, "SCROLLBAR") == 0)
  1523. is_scrollbar_group = TRUE;
  1524. #endif
  1525.     if (doclear)
  1526. highlight_clear(idx);
  1527.     else
  1528.       while (!ends_excmd(*linep))
  1529.       {
  1530. key_start = linep;
  1531. if (*linep == '=')
  1532. {
  1533.     EMSG2("unexpected equal sign: %s", key_start);
  1534.     error = TRUE;
  1535.     break;
  1536. }
  1537. /*
  1538.  * Isolate the key ("term", "ctermfg", "ctermbg", "font", "guifg" or
  1539.  * "guibg").
  1540.  */
  1541. while (*linep && !vim_iswhite(*linep) && *linep != '=')
  1542.     ++linep;
  1543. vim_free(key);
  1544. key = vim_strnsave_up(key_start, (int)(linep - key_start));
  1545. if (key == NULL)
  1546. {
  1547.     error = TRUE;
  1548.     break;
  1549. }
  1550. linep = skipwhite(linep);
  1551. if (STRCMP(key, "NONE") == 0)
  1552. {
  1553.     if (!init || HL_TABLE()[idx].sg_set == 0)
  1554.     {
  1555. if (!init)
  1556.     HL_TABLE()[idx].sg_set |= SG_TERM+SG_CTERM+SG_GUI;
  1557. highlight_clear(idx);
  1558.     }
  1559.     continue;
  1560. }
  1561. /*
  1562.  * Check for the equal sign.
  1563.  */
  1564. if (*linep != '=')
  1565. {
  1566.     EMSG2("missing equal sign: %s", key_start);
  1567.     error = TRUE;
  1568.     break;
  1569. }
  1570. ++linep;
  1571. /*
  1572.  * Isolate the argument.
  1573.  */
  1574. linep = skipwhite(linep);
  1575. if (*linep == ''') /* guifg='color name' */
  1576. {
  1577.     arg_start = ++linep;
  1578.     linep = vim_strchr(linep, ''');
  1579. }
  1580. else
  1581. {
  1582.     arg_start = linep;
  1583.     linep = skiptowhite(linep);
  1584. }
  1585. if (linep == arg_start)
  1586. {
  1587.     EMSG2("missing argument: %s", key_start);
  1588.     error = TRUE;
  1589.     break;
  1590. }
  1591. vim_free(arg);
  1592. arg = vim_strnsave(arg_start, (int)(linep - arg_start));
  1593. if (arg == NULL)
  1594. {
  1595.     error = TRUE;
  1596.     break;
  1597. }
  1598. if (*linep == ''')
  1599.     ++linep;
  1600. /*
  1601.  * Store the argument.
  1602.  */
  1603. if (  STRCMP(key, "TERM") == 0
  1604. || STRCMP(key, "CTERM") == 0
  1605. || STRCMP(key, "GUI") == 0)
  1606. {
  1607.     attr = 0;
  1608.     off = 0;
  1609.     while (arg[off] != NUL)
  1610.     {
  1611. for (i = sizeof(hl_attr_table) / sizeof(int); --i >= 0; )
  1612. {
  1613.     len = STRLEN(hl_name_table[i]);
  1614.     if (STRNICMP(arg + off, hl_name_table[i], len) == 0)
  1615.     {
  1616. attr |= hl_attr_table[i];
  1617. off += len;
  1618. break;
  1619.     }
  1620. }
  1621. if (i < 0)
  1622. {
  1623.     EMSG2("Illegal value: %s", arg);
  1624.     error = TRUE;
  1625.     break;
  1626. }
  1627. if (arg[off] == ',') /* another one follows */
  1628.     ++off;
  1629.     }
  1630.     if (error)
  1631. break;
  1632.     if (*key == 'T')
  1633.     {
  1634. if (!init || !(HL_TABLE()[idx].sg_set & SG_TERM))
  1635. {
  1636.     if (!init)
  1637. HL_TABLE()[idx].sg_set |= SG_TERM;
  1638.     HL_TABLE()[idx].sg_term = attr;
  1639. }
  1640.     }
  1641.     else if (*key == 'C')
  1642.     {
  1643. if (!init || !(HL_TABLE()[idx].sg_set & SG_CTERM))
  1644. {
  1645.     if (!init)
  1646. HL_TABLE()[idx].sg_set |= SG_CTERM;
  1647.     HL_TABLE()[idx].sg_cterm = attr;
  1648.     HL_TABLE()[idx].sg_cterm_bold = FALSE;
  1649. }
  1650.     }
  1651. #ifdef USE_GUI
  1652.     else
  1653.     {
  1654. if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI))
  1655. {
  1656.     if (!init)
  1657. HL_TABLE()[idx].sg_set |= SG_GUI;
  1658.     HL_TABLE()[idx].sg_gui = attr;
  1659. }
  1660.     }
  1661. #endif
  1662. }
  1663. else if (STRCMP(key, "FONT") == 0)
  1664. {
  1665. #ifdef USE_GUI     /* in non-GUI fonts are simply ignored */
  1666.     gui_mch_free_font(HL_TABLE()[idx].sg_font);
  1667.     HL_TABLE()[idx].sg_font = font_name2handle(arg);
  1668.     vim_free(HL_TABLE()[idx].sg_font_name);
  1669.     HL_TABLE()[idx].sg_font_name = vim_strsave(arg);
  1670.     if (is_normal_group)
  1671. gui_init_font(arg);
  1672. #endif
  1673. }
  1674. else if (STRCMP(key, "CTERMFG") == 0 || STRCMP(key, "CTERMBG") == 0)
  1675. {
  1676.   if (!init || !(HL_TABLE()[idx].sg_set & SG_CTERM))
  1677.   {
  1678.     if (!init)
  1679. HL_TABLE()[idx].sg_set |= SG_CTERM;
  1680.     /* When setting the foreground color, and previously the "bold"
  1681.      * flag was set for a light color, reset it now */
  1682.     if (key[5] == 'F' && HL_TABLE()[idx].sg_cterm_bold)
  1683.     {
  1684. HL_TABLE()[idx].sg_cterm &= ~HL_BOLD;
  1685. HL_TABLE()[idx].sg_cterm_bold = FALSE;
  1686.     }
  1687.     if (isdigit(*arg))
  1688. color = atoi((char *)arg);
  1689.     else
  1690.     {
  1691. static char *(color_names[26]) = {
  1692.     "Black", "DarkBlue", "DarkGreen", "DarkCyan",
  1693.     "DarkRed", "DarkMagenta", "Brown", "Gray", "Grey",
  1694.     "LightGray", "LightGrey", "DarkGray", "DarkGrey",
  1695.     "Blue", "LightBlue", "Green", "LightGreen",
  1696.     "Cyan", "LightCyan", "Red", "LightRed", "Magenta",
  1697.     "LightMagenta", "Yellow", "White", "NONE"};
  1698. static int color_numbers_16[26] = {0, 1, 2, 3,
  1699.  4, 5, 6, 7, 7,
  1700.  7, 7, 8, 8,
  1701.  9, 9, 10, 10,
  1702.  11, 11, 12, 12, 13,
  1703.  13, 14, 15, -1};
  1704. /* for terminals with less than 16 colors... */
  1705. static int color_numbers_8[26] = {0, 4, 2, 6,
  1706.  1, 5, 3, 7, 7,
  1707.  7, 7, 0+8, 0+8,
  1708.  4+8, 4+8, 2+8, 2+8,
  1709.  6+8, 6+8, 1+8, 1+8, 5+8,
  1710.  5+8, 3+8, 7+8, -1};
  1711. /* reduce calls to STRICMP a bit, it can be slow */
  1712. off = TO_UPPER(*arg);
  1713. for (i = (sizeof(color_names) / sizeof(char *)); --i >= 0; )
  1714.     if (off == color_names[i][0]
  1715.  && STRICMP(arg + 1, color_names[i] + 1) == 0)
  1716. break;
  1717. if (i < 0)
  1718. {
  1719.     EMSG2("Color name or number not recognized: %s", key_start);
  1720.     error = TRUE;
  1721.     break;
  1722. }
  1723. color = color_numbers_16[i];
  1724. if (color >= 0)
  1725. {
  1726.     if (atoi((char *)T_CCO) == 8)
  1727.     {
  1728. color = color_numbers_8[i];
  1729. if (key[5] == 'F')
  1730. {
  1731.     /* set/reset bold attribute to get light foreground
  1732.      * colors (on some terminals, e.g. "linux") */
  1733.     if (color & 8)
  1734.     {
  1735. HL_TABLE()[idx].sg_cterm |= HL_BOLD;
  1736. HL_TABLE()[idx].sg_cterm_bold = TRUE;
  1737.     }
  1738.     else
  1739. HL_TABLE()[idx].sg_cterm &= ~HL_BOLD;
  1740. }
  1741. color &= 7;
  1742.     }
  1743.     else if (atoi((char *)T_CCO) == 16)
  1744.     {
  1745. /*
  1746.  * Guess: if the termcap entry ends in 'm', it is
  1747.  * probably an xterm-like terminal.  Use the changed
  1748.  * order for colors.
  1749.  */
  1750. if (*T_CAF != NUL)
  1751.     p = T_CAF;
  1752. else
  1753.     p = T_CSF;
  1754. if (*p != NUL && *(p + STRLEN(p) - 1) == 'm')
  1755.     color = color_numbers_8[i];
  1756.     }
  1757. }
  1758.     }
  1759.     /* Add one to the argument, to avoid zero */
  1760.     if (key[5] == 'F')
  1761.     {
  1762. HL_TABLE()[idx].sg_cterm_fg = color + 1;
  1763. if (is_normal_group)
  1764. {
  1765.     cterm_normal_fg_color = color + 1;
  1766.     cterm_normal_fg_bold = (HL_TABLE()[idx].sg_cterm & HL_BOLD);
  1767.     must_redraw = CLEAR;
  1768.     term_fg_color(color);
  1769. }
  1770.     }
  1771.     else
  1772.     {
  1773. HL_TABLE()[idx].sg_cterm_bg = color + 1;
  1774. if (is_normal_group)
  1775. {
  1776.     cterm_normal_bg_color = color + 1;
  1777.     must_redraw = CLEAR;
  1778.     term_bg_color(color);
  1779.     if (atoi((char *)T_CCO) < 16)
  1780. i = (color == 0 || color == 4);
  1781.     else
  1782. i = (color < 7 || color == 8);
  1783.     set_option_value((char_u *)"bg", 0L,
  1784.     i ? (char_u *)"dark" : (char_u *)"light");
  1785. }
  1786.     }
  1787.   }
  1788. }
  1789. else if (STRCMP(key, "GUIFG") == 0)
  1790. {
  1791. #ifdef USE_GUI     /* in non-GUI guifg colors are simply ignored */
  1792.   if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI))
  1793.   {
  1794.     if (!init)
  1795. HL_TABLE()[idx].sg_set |= SG_GUI;
  1796.     /* Add one to the argument, to avoid zero */
  1797.     i = color_name2handle(arg) + 1;
  1798.     if (i > 0 || STRCMP(arg, "NONE") == 0 || !gui.in_use)
  1799.     {
  1800. HL_TABLE()[idx].sg_gui_fg = i;
  1801. vim_free(HL_TABLE()[idx].sg_gui_fg_name);
  1802. if (STRCMP(arg, "NONE"))
  1803.     HL_TABLE()[idx].sg_gui_fg_name = vim_strsave(arg);
  1804. else
  1805.     HL_TABLE()[idx].sg_gui_fg_name = NULL;
  1806. # ifdef USE_GUI_X11
  1807. if (is_menu_group)
  1808.     gui.menu_fg_pixel = i - 1;
  1809. if (is_scrollbar_group)
  1810.     gui.scroll_fg_pixel = i - 1;
  1811. # endif
  1812.     }
  1813.   }
  1814. #endif
  1815. }
  1816. else if (STRCMP(key, "GUIBG") == 0)
  1817. {
  1818. #ifdef USE_GUI     /* in non-GUI guibg colors are simply ignored */
  1819.   if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI))
  1820.   {
  1821.     if (!init)
  1822. HL_TABLE()[idx].sg_set |= SG_GUI;
  1823.     /* Add one to the argument, to avoid zero */
  1824.     i = color_name2handle(arg) + 1;
  1825.     if (i > 0 || STRCMP(arg, "NONE") == 0 || !gui.in_use)
  1826.     {
  1827. HL_TABLE()[idx].sg_gui_bg = i;
  1828. vim_free(HL_TABLE()[idx].sg_gui_bg_name);
  1829. if (STRCMP(arg, "NONE"))
  1830.     HL_TABLE()[idx].sg_gui_bg_name = vim_strsave(arg);
  1831. else
  1832.     HL_TABLE()[idx].sg_gui_bg_name = NULL;
  1833. # ifdef USE_GUI_X11
  1834. if (is_menu_group)
  1835.     gui.menu_bg_pixel = i - 1;
  1836. if (is_scrollbar_group)
  1837.     gui.scroll_bg_pixel = i - 1;
  1838. # endif
  1839.     }
  1840.   }
  1841. #endif
  1842. }
  1843. else if (STRCMP(key, "START") == 0 || STRCMP(key, "STOP") == 0)
  1844. {
  1845.     char_u buf[100];
  1846.     char_u *tname;
  1847.     if (!init)
  1848. HL_TABLE()[idx].sg_set |= SG_TERM;
  1849.     /*
  1850.      * The "start" and "stop"  arguments can be a literal escape
  1851.      * sequence, or a comma seperated list of terminal codes.
  1852.      */
  1853.     if (STRNCMP(arg, "t_", 2) == 0)
  1854.     {
  1855. off = 0;
  1856. buf[0] = 0;
  1857. while (arg[off] != NUL)
  1858. {
  1859.     /* Isolate one termcap name */
  1860.     for (len = 0; arg[off + len] &&
  1861.  arg[off + len] != ','; ++len)
  1862. ;
  1863.     tname = vim_strnsave(arg + off, len);
  1864.     if (tname == NULL) /* out of memory */
  1865.     {
  1866. error = TRUE;
  1867. break;
  1868.     }
  1869.     /* lookup the escape sequence for the item */
  1870.     p = get_term_code(tname);
  1871.     vim_free(tname);
  1872.     if (p == NULL)     /* ignore non-existing things */
  1873. p = (char_u *)"";
  1874.     /* Append it to the already found stuff */
  1875.     if ((int)(STRLEN(buf) + STRLEN(p)) >= 99)
  1876.     {
  1877. EMSG2("terminal code too long: %s", arg);
  1878. error = TRUE;
  1879. break;
  1880.     }
  1881.     STRCAT(buf, p);
  1882.     /* Advance to the next item */
  1883.     off += len;
  1884.     if (arg[off] == ',')     /* another one follows */
  1885. ++off;
  1886. }
  1887.     }
  1888.     else
  1889.     {
  1890. /*
  1891.  * Copy characters from arg[] to buf[], translating <> codes.
  1892.  */
  1893. for (p = arg, off = 0; off < 100 && *p; )
  1894. {
  1895.     len = trans_special(&p, buf + off, FALSE);
  1896.     if (len)     /* recognized special char */
  1897. off += len;
  1898.     else     /* copy as normal char */
  1899. buf[off++] = *p++;
  1900. }
  1901. buf[off] = NUL;
  1902.     }
  1903.     if (error)
  1904. break;
  1905.     if (STRCMP(buf, "NONE") == 0) /* resetting the value */
  1906. p = NULL;
  1907.     else
  1908. p = vim_strsave(buf);
  1909.     if (key[2] == 'A')
  1910.     {
  1911. vim_free(HL_TABLE()[idx].sg_start);
  1912. HL_TABLE()[idx].sg_start = p;
  1913.     }
  1914.     else
  1915.     {
  1916. vim_free(HL_TABLE()[idx].sg_stop);
  1917. HL_TABLE()[idx].sg_stop = p;
  1918.     }
  1919. }
  1920. else
  1921. {
  1922.     EMSG2("Illegal argument: %s", key_start);
  1923.     error = TRUE;
  1924.     break;
  1925. }
  1926. /*
  1927.  * When highlighting has been given for a group, don't link it.
  1928.  */
  1929. if (!init || !(HL_TABLE()[idx].sg_set & SG_LINK))
  1930.     HL_TABLE()[idx].sg_link = 0;
  1931. /*
  1932.  * Continue with next argument.
  1933.  */
  1934. linep = skipwhite(linep);
  1935.       }
  1936.     /*
  1937.      * If there is an error, and it's a new entry, remove it from the table.
  1938.      */
  1939.     if (error && idx == highlight_ga.ga_len)
  1940. syn_unadd_group();
  1941.     else
  1942.     {
  1943. if (is_normal_group)
  1944. {
  1945.     HL_TABLE()[idx].sg_term_attr = 0;
  1946.     HL_TABLE()[idx].sg_cterm_attr = 0;
  1947. #ifdef USE_GUI
  1948.     HL_TABLE()[idx].sg_gui_attr = 0;
  1949.     /*
  1950.      * Need to update all groups, because they might be using "bg"
  1951.      * and/or "fg", which have been changed now.
  1952.      */
  1953.     if (gui.in_use)
  1954. highlight_gui_started();
  1955. #endif
  1956. }
  1957. #ifdef USE_GUI_X11
  1958. else if (is_menu_group)
  1959.     gui_mch_new_menu_colors();
  1960. else if (is_scrollbar_group)
  1961. {
  1962.     if (gui.in_use)
  1963. gui_new_scrollbar_colors();
  1964. }
  1965. #endif
  1966. else
  1967.     set_hl_attr(idx);
  1968. redraw_all_later(NOT_VALID);
  1969.     }
  1970.     vim_free(key);
  1971.     vim_free(arg);
  1972.     /* Only call highlight_changed() once, after sourcing a syntax file */
  1973.     need_highlight_changed = TRUE;
  1974. }
  1975. /*
  1976.  * List highlighting matches in a nice way.
  1977.  */
  1978.     static void
  1979. highlight_list()
  1980. {
  1981.     int i;
  1982.     for (i = 10; --i >= 0; )
  1983. highlight_list_two(i, hl_attr(HLF_D));
  1984.     for (i = 40; --i >= 0; )
  1985. highlight_list_two(55, 0);
  1986. }
  1987. /*
  1988.  * Clear highlighting for one group.
  1989.  */
  1990.     static void
  1991. highlight_clear(idx)
  1992.     int idx;
  1993. {
  1994.     HL_TABLE()[idx].sg_term = 0;
  1995.     vim_free(HL_TABLE()[idx].sg_start);
  1996.     HL_TABLE()[idx].sg_start = NULL;
  1997.     vim_free(HL_TABLE()[idx].sg_stop);
  1998.     HL_TABLE()[idx].sg_stop = NULL;
  1999.     HL_TABLE()[idx].sg_term_attr = 0;
  2000.     HL_TABLE()[idx].sg_cterm = 0;
  2001.     HL_TABLE()[idx].sg_cterm_bold = FALSE;
  2002.     HL_TABLE()[idx].sg_cterm_fg = 0;
  2003.     HL_TABLE()[idx].sg_cterm_bg = 0;
  2004.     HL_TABLE()[idx].sg_cterm_attr = 0;
  2005. #ifdef USE_GUI     /* in non-GUI fonts are simply ignored */
  2006.     HL_TABLE()[idx].sg_gui = 0;
  2007.     HL_TABLE()[idx].sg_gui_fg = 0;
  2008.     vim_free(HL_TABLE()[idx].sg_gui_fg_name);
  2009.     HL_TABLE()[idx].sg_gui_fg_name = NULL;
  2010.     HL_TABLE()[idx].sg_gui_bg = 0;
  2011.     vim_free(HL_TABLE()[idx].sg_gui_bg_name);
  2012.     HL_TABLE()[idx].sg_gui_bg_name = NULL;
  2013.     gui_mch_free_font(HL_TABLE()[idx].sg_font);
  2014.     HL_TABLE()[idx].sg_font = 0;
  2015.     vim_free(HL_TABLE()[idx].sg_font_name);
  2016.     HL_TABLE()[idx].sg_font_name = NULL;
  2017.     HL_TABLE()[idx].sg_gui_attr = 0;
  2018. #endif
  2019. }
  2020. #ifdef USE_GUI
  2021. /*
  2022.  * Set the normal foreground and background colors according to the "Normal"
  2023.  * highlighighting group.  For X11 also set "Menu" and "Scrollbar" colors.
  2024.  */
  2025.     void
  2026. set_normal_colors()
  2027. {
  2028.     if (set_group_colors((char_u *)"Normal",
  2029.     &gui.norm_pixel, &gui.back_pixel))
  2030.     {
  2031. gui_mch_new_colors();
  2032. must_redraw = CLEAR;
  2033.     }
  2034. #ifdef USE_GUI_X11
  2035.     if (set_group_colors((char_u *)"Menu",
  2036.       &gui.menu_fg_pixel, &gui.menu_bg_pixel))
  2037.     {
  2038. gui_mch_new_menu_colors();
  2039. must_redraw = CLEAR;
  2040.     }
  2041.     if (set_group_colors((char_u *)"Scrollbar",
  2042.   &gui.scroll_fg_pixel, &gui.scroll_bg_pixel))
  2043.     {
  2044. gui_new_scrollbar_colors();
  2045. must_redraw = CLEAR;
  2046.     }
  2047. #endif
  2048. }
  2049. /*
  2050.  * Set the colors for "Normal", "Menu" or "Scrollbar".
  2051.  */
  2052.     static int
  2053. set_group_colors(name, fgp, bgp)
  2054.     char_u *name;
  2055.     GuiColor *fgp;
  2056.     GuiColor *bgp;
  2057. {
  2058.     int idx;
  2059.     idx = syn_name2id(name) - 1;
  2060.     if (idx >= 0)
  2061.     {
  2062. gui_do_one_color(idx);
  2063. if (HL_TABLE()[idx].sg_gui_fg > 0)
  2064.     *fgp = HL_TABLE()[idx].sg_gui_fg - 1;
  2065. else
  2066.     *fgp = gui.def_norm_pixel;
  2067. if (HL_TABLE()[idx].sg_gui_bg > 0)
  2068.     *bgp = HL_TABLE()[idx].sg_gui_bg - 1;
  2069. else
  2070.     *bgp = gui.def_back_pixel;
  2071. return TRUE;
  2072.     }
  2073.     return FALSE;
  2074. }
  2075. /*
  2076.  * Set font for "Normal" group.  Called by gui_mch_init_font() when a font has
  2077.  * actually chosen to be used.
  2078.  */
  2079.     void
  2080. hl_set_font_name(font_name)
  2081.     char_u *font_name;
  2082. {
  2083.     int     id;
  2084.     id = syn_name2id((char_u *)"Normal");
  2085.     if (id > 0)
  2086.     {
  2087. vim_free(HL_TABLE()[id - 1].sg_font_name);
  2088. HL_TABLE()[id - 1].sg_font_name = vim_strsave(font_name);
  2089.     }
  2090. }
  2091. /*
  2092.  * Set background color for "Normal" group.  Called by gui_mch_init()
  2093.  * when the color is known.
  2094.  */
  2095.     void
  2096. hl_set_bg_color_name(name)
  2097.     char_u  *name;     /* must have been allocated */
  2098. {
  2099.     int     id;
  2100.     if (name != NULL)
  2101.     {
  2102. id = syn_name2id((char_u *)"Normal");
  2103. if (id > 0)
  2104. {
  2105.     vim_free(HL_TABLE()[id - 1].sg_gui_bg_name);
  2106.     HL_TABLE()[id - 1].sg_gui_bg_name = name;
  2107. }
  2108.     }
  2109. }
  2110. /*
  2111.  * Set foreground color for "Normal" group.  Called by gui_mch_init()
  2112.  * when the color is known.
  2113.  */
  2114.     void
  2115. hl_set_fg_color_name(name)
  2116.     char_u  *name;     /* must have been allocated */
  2117. {
  2118.     int     id;
  2119.     if (name != NULL)
  2120.     {
  2121. id = syn_name2id((char_u *)"Normal");
  2122. if (id > 0)
  2123. {
  2124.     vim_free(HL_TABLE()[id - 1].sg_gui_fg_name);
  2125.     HL_TABLE()[id - 1].sg_gui_fg_name = name;
  2126. }
  2127.     }
  2128. }
  2129. /*
  2130.  * Return the handle for a color name.
  2131.  * Returns -1 when failed.
  2132.  */
  2133.     static GuiColor
  2134. color_name2handle(name)
  2135.     char_u  *name;
  2136. {
  2137.     if (STRCMP(name, "NONE") == 0)
  2138. return (GuiColor)-1;
  2139.     if (STRICMP(name, "fg") == 0 || STRICMP(name, "foreground") == 0)
  2140. return gui.norm_pixel;
  2141.     if (STRICMP(name, "bg") == 0 || STRICMP(name, "background") == 0)
  2142. return gui.back_pixel;
  2143.     return gui_mch_get_color(name);
  2144. }
  2145. /*
  2146.  * Return the handle for a font name.
  2147.  * Returns 0 when failed.
  2148.  */
  2149.     static GuiFont
  2150. font_name2handle(name)
  2151.     char_u  *name;
  2152. {
  2153.     if (STRCMP(name, "NONE") == 0)
  2154. return (GuiFont)0;
  2155.     return gui_mch_get_font(name, TRUE);
  2156. }
  2157. #endif /* USE_GUI */
  2158. /*
  2159.  * Table with the specifications for an attribute number.
  2160.  * Note that this table is used by ALL buffers.  This is required because the
  2161.  * GUI can redraw at any time for any buffer.
  2162.  */
  2163. struct growarray    term_attr_table = {0, 0, 0, 0, NULL};
  2164. #define TERM_ATTR_ENTRY(idx) ((struct attr_entry *)term_attr_table.ga_data)[idx]
  2165. struct growarray    cterm_attr_table = {0, 0, 0, 0, NULL};
  2166. #define CTERM_ATTR_ENTRY(idx) ((struct attr_entry *)cterm_attr_table.ga_data)[idx]
  2167. #ifdef USE_GUI
  2168. struct growarray    gui_attr_table = {0, 0, 0, 0, NULL};
  2169. #define GUI_ATTR_ENTRY(idx) ((struct attr_entry *)gui_attr_table.ga_data)[idx]
  2170. #endif
  2171. /*
  2172.  * Return the attr number for a set of colors and font.
  2173.  * Add a new entry to the term_attr_table, cterm_attr_table or gui_attr_table
  2174.  * if the combination is new.
  2175.  * Return 0 for error (no more room).
  2176.  */
  2177.     static int
  2178. get_attr_entry(table, aep)
  2179.     struct growarray *table;
  2180.     struct attr_entry *aep;
  2181. {
  2182.     int i;
  2183.     struct attr_entry *gap;
  2184.     static int recursive = FALSE;
  2185.     /*
  2186.      * Init the table, in case it wasn't done yet.
  2187.      */
  2188.     table->ga_itemsize = sizeof(struct attr_entry);
  2189.     table->ga_growsize = 7;
  2190.     /*
  2191.      * Try to find an entry with the same specifications.
  2192.      */
  2193.     for (i = 0; i < table->ga_len; ++i)
  2194.     {
  2195. gap = &(((struct attr_entry *)table->ga_data)[i]);
  2196. if (    aep->ae_attr == gap->ae_attr
  2197. && (
  2198. #ifdef USE_GUI
  2199.        (table == &gui_attr_table
  2200. && (aep->ae_u.gui.fg_color == gap->ae_u.gui.fg_color
  2201.     && aep->ae_u.gui.bg_color == gap->ae_u.gui.bg_color
  2202.     && aep->ae_u.gui.font == gap->ae_u.gui.font))
  2203.     ||
  2204. #endif
  2205.        (table == &term_attr_table
  2206. && (aep->ae_u.term.start == NULL) ==
  2207. (gap->ae_u.term.start == NULL)
  2208. && (aep->ae_u.term.start == NULL
  2209.     || STRCMP(aep->ae_u.term.start,
  2210.    gap->ae_u.term.start) == 0)
  2211. && (aep->ae_u.term.stop == NULL) ==
  2212.  (gap->ae_u.term.stop == NULL)
  2213. && (aep->ae_u.term.stop == NULL
  2214.     || STRCMP(aep->ae_u.term.stop,
  2215.    gap->ae_u.term.stop) == 0))
  2216.     || (table == &cterm_attr_table
  2217. && aep->ae_u.cterm.fg_color == gap->ae_u.cterm.fg_color
  2218. && aep->ae_u.cterm.bg_color == gap->ae_u.cterm.bg_color)
  2219.      ))
  2220. return i + ATTR_OFF;
  2221.     }
  2222.     if (table->ga_len + ATTR_OFF == 256)
  2223.     {
  2224. /*
  2225.  * Running out of attribute entries!  remove all attributes, and
  2226.  * compute new ones for all groups.
  2227.  * When called recursively, we are really out of numbers.
  2228.  */
  2229. if (recursive)
  2230. {
  2231.     EMSG("Too many different highlighting attributes in use");
  2232.     return 0;
  2233. }
  2234. recursive = TRUE;
  2235. #ifdef USE_GUI
  2236. ga_clear(&gui_attr_table);
  2237. #endif
  2238. ga_clear(&term_attr_table);
  2239. ga_clear(&cterm_attr_table);
  2240. must_redraw = CLEAR;
  2241. for (i = 0; i < highlight_ga.ga_len; ++i)
  2242.     set_hl_attr(i);
  2243. recursive = FALSE;
  2244.     }
  2245.     /*
  2246.      * This is a new combination of colors and font, add an entry.
  2247.      */
  2248.     if (ga_grow(table, 1) == FAIL)
  2249. return 0;
  2250.     gap = &(((struct attr_entry *)table->ga_data)[table->ga_len]);
  2251.     vim_memset(gap, 0, sizeof(struct attr_entry));
  2252.     gap->ae_attr = aep->ae_attr;
  2253. #ifdef USE_GUI
  2254.     if (table == &gui_attr_table)
  2255.     {
  2256. gap->ae_u.gui.fg_color = aep->ae_u.gui.fg_color;
  2257. gap->ae_u.gui.bg_color = aep->ae_u.gui.bg_color;
  2258. gap->ae_u.gui.font = aep->ae_u.gui.font;
  2259.     }
  2260. #endif
  2261.     if (table == &term_attr_table)
  2262.     {
  2263. if (aep->ae_u.term.start == NULL)
  2264.     gap->ae_u.term.start = NULL;
  2265. else
  2266.     gap->ae_u.term.start = vim_strsave(aep->ae_u.term.start);
  2267. if (aep->ae_u.term.stop == NULL)
  2268.     gap->ae_u.term.stop = NULL;
  2269. else
  2270.     gap->ae_u.term.stop = vim_strsave(aep->ae_u.term.stop);
  2271.     }
  2272.     else if (table == &cterm_attr_table)
  2273.     {
  2274. gap->ae_u.cterm.fg_color = aep->ae_u.cterm.fg_color;
  2275. gap->ae_u.cterm.bg_color = aep->ae_u.cterm.bg_color;
  2276.     }
  2277.     ++table->ga_len;
  2278.     --table->ga_room;
  2279.     return (table->ga_len - 1 + ATTR_OFF);
  2280. }
  2281. #ifdef USE_GUI
  2282.     struct attr_entry *
  2283. syn_gui_attr2entry(attr)
  2284.     int     attr;
  2285. {
  2286.     attr -= ATTR_OFF;
  2287.     if (attr >= gui_attr_table.ga_len)     /* did ":syntax clear" */
  2288. return NULL;
  2289.     return &(GUI_ATTR_ENTRY(attr));
  2290. }
  2291. #endif /* USE_GUI */
  2292.     struct attr_entry *
  2293. syn_term_attr2entry(attr)
  2294.     int     attr;
  2295. {
  2296.     attr -= ATTR_OFF;
  2297.     if (attr >= term_attr_table.ga_len)     /* did ":syntax clear" */
  2298. return NULL;
  2299.     return &(TERM_ATTR_ENTRY(attr));
  2300. }
  2301.     struct attr_entry *
  2302. syn_cterm_attr2entry(attr)
  2303.     int     attr;
  2304. {
  2305.     attr -= ATTR_OFF;
  2306.     if (attr >= cterm_attr_table.ga_len) /* did ":syntax clear" */
  2307. return NULL;
  2308.     return &(CTERM_ATTR_ENTRY(attr));
  2309. }
  2310. #define LIST_ATTR   1
  2311. #define LIST_STRING 2
  2312. #define LIST_INT    3
  2313.     static void
  2314. highlight_list_one(id)
  2315.     int id;
  2316. {
  2317.     struct hl_group *sgp;
  2318.     int didh = FALSE;
  2319.     sgp = &HL_TABLE()[id - 1];     /* index is ID minus one */
  2320.     didh = highlight_list_arg(id, didh, LIST_ATTR,
  2321.     sgp->sg_term, NULL, "term");
  2322.     didh = highlight_list_arg(id, didh, LIST_STRING,
  2323.     0, sgp->sg_start, "start");
  2324.     didh = highlight_list_arg(id, didh, LIST_STRING,
  2325.     0, sgp->sg_stop, "stop");
  2326.     didh = highlight_list_arg(id, didh, LIST_ATTR,
  2327.     sgp->sg_cterm, NULL, "cterm");
  2328.     didh = highlight_list_arg(id, didh, LIST_INT,
  2329.     sgp->sg_cterm_fg, NULL, "ctermfg");
  2330.     didh = highlight_list_arg(id, didh, LIST_INT,
  2331.     sgp->sg_cterm_bg, NULL, "ctermbg");
  2332. #ifdef USE_GUI
  2333.     didh = highlight_list_arg(id, didh, LIST_ATTR,
  2334.     sgp->sg_gui, NULL, "gui");
  2335.     didh = highlight_list_arg(id, didh, LIST_STRING,
  2336.     0, sgp->sg_gui_fg_name, "guifg");
  2337.     didh = highlight_list_arg(id, didh, LIST_STRING,
  2338.     0, sgp->sg_gui_bg_name, "guibg");
  2339.     didh = highlight_list_arg(id, didh, LIST_STRING,
  2340.     0, sgp->sg_font_name, "font");
  2341. #endif
  2342.     if (sgp->sg_link)
  2343.     {
  2344. (void)syn_list_header(didh, 9999, id);
  2345. msg_puts_attr((char_u *)"links to", hl_attr(HLF_D));
  2346. msg_putchar(' ');
  2347. msg_outtrans(HL_TABLE()[HL_TABLE()[id - 1].sg_link - 1].sg_name);
  2348.     }
  2349. }
  2350.     static void
  2351. highlight_list_two(cnt, attr)
  2352.     int     cnt;
  2353.     int     attr;
  2354. {
  2355.     msg_puts_attr((char_u *)("NI!  b" + cnt/11), attr);
  2356.     msg_clr_eos();
  2357.     out_flush();
  2358.     ui_delay(cnt == 55 ? 40L : (long)cnt*50L, FALSE);
  2359. }
  2360.     static int
  2361. highlight_list_arg(id, didh, type, iarg, sarg, name)
  2362.     int id;
  2363.     int didh;
  2364.     int type;
  2365.     int iarg;
  2366.     char_u *sarg;
  2367.     char *name;
  2368. {
  2369.     char_u buf[100];
  2370.     char_u *ts;
  2371.     int i;
  2372.     if (type == LIST_STRING ? (sarg != NULL) : (iarg != 0))
  2373.     {
  2374. ts = buf;
  2375. if (type == LIST_INT)
  2376.     sprintf((char *)buf, "%d", iarg - 1);
  2377. else if (type == LIST_STRING)
  2378.     ts = sarg;
  2379. else /* type == LIST_ATTR */
  2380. {
  2381.     buf[0] = NUL;
  2382.     for (i = 0; hl_attr_table[i] != 0; ++i)
  2383.     {
  2384. if (iarg & hl_attr_table[i])
  2385. {
  2386.     if (buf[0] != NUL)
  2387. STRCAT(buf, ",");
  2388.     STRCAT(buf, hl_name_table[i]);
  2389.     iarg &= ~hl_attr_table[i];     /* don't want "inverse" */
  2390. }
  2391.     }
  2392. }
  2393. (void)syn_list_header(didh,
  2394.        (int)(vim_strsize(ts) + STRLEN(name) + 1), id);
  2395. didh = TRUE;
  2396. MSG_PUTS_ATTR(name, hl_attr(HLF_D));
  2397. MSG_PUTS_ATTR("=", hl_attr(HLF_D));
  2398. msg_outtrans(ts);
  2399.     }
  2400.     return didh;
  2401. }
  2402. /*
  2403.  * Return "1" if highlight group "id" has attribute "flag".
  2404.  * Return NULL otherwise.
  2405.  */
  2406.     char_u *
  2407. highlight_has_attr(id, flag, modec)
  2408.     int id;
  2409.     int flag;
  2410.     int modec; /* 'g' for GUI, 'c' for cterm, 't' for term */
  2411. {
  2412.     int attr;
  2413.     if (id <= 0 || id > highlight_ga.ga_len)
  2414. return NULL;
  2415. #ifdef USE_GUI
  2416.     if (modec == 'g')
  2417. attr = HL_TABLE()[id - 1].sg_gui;
  2418.     else
  2419. #endif
  2420.  if (modec == 'c')
  2421. attr = HL_TABLE()[id - 1].sg_cterm;
  2422.     else
  2423. attr = HL_TABLE()[id - 1].sg_term;
  2424.     if (attr & flag)
  2425. return (char_u *)"1";
  2426.     return NULL;
  2427. }
  2428. /*
  2429.  * Return color name of highlight group "id".
  2430.  */
  2431.     char_u *
  2432. highlight_color(id, what, modec)
  2433.     int id;
  2434.     char_u *what; /* "fg", "bg", "fg#" or "bg#" */
  2435.     int modec; /* 'g' for GUI, 'c' for cterm, 't' for term */
  2436. {
  2437.     static char_u name[20];
  2438.     int n;
  2439.     int fg;
  2440.     if (id <= 0 || id > highlight_ga.ga_len)
  2441. return NULL;
  2442.     if (TO_LOWER(what[0]) == 'f')
  2443. fg = TRUE;
  2444.     else
  2445. fg = FALSE;
  2446. #ifdef USE_GUI
  2447.     if (modec == 'g')
  2448.     {
  2449. /* return #RRGGBB form (only possible when GUI is running) */
  2450. if (gui.in_use && what[1] && what[2] == '#')
  2451. {
  2452.     GuiColor color;
  2453.     if (fg)
  2454. color = HL_TABLE()[id - 1].sg_gui_fg;
  2455.     else
  2456. color = HL_TABLE()[id - 1].sg_gui_bg;
  2457.     if (color == 0)
  2458. return NULL;
  2459.     return gui_mch_get_rgb(color - 1);
  2460. }
  2461. if (fg)
  2462.     return (HL_TABLE()[id - 1].sg_gui_fg_name);
  2463. return (HL_TABLE()[id - 1].sg_gui_bg_name);
  2464.     }
  2465. #endif
  2466.     if (modec == 'c')
  2467.     {
  2468. if (fg)
  2469.     n = HL_TABLE()[id - 1].sg_cterm_fg - 1;
  2470. else
  2471.     n = HL_TABLE()[id - 1].sg_cterm_bg - 1;
  2472. sprintf((char *)name, "%d", n);
  2473. return name;
  2474.     }
  2475.     /* term doesn't have color */
  2476.     return NULL;
  2477. }
  2478. /*
  2479.  * Output the syntax list header.
  2480.  * Return TRUE when started a new line.
  2481.  */
  2482.     static int
  2483. syn_list_header(did_header, outlen, id)
  2484.     int     did_header; /* did header already */
  2485.     int     outlen; /* length of string that comes */
  2486.     int     id; /* highlight group id */
  2487. {
  2488.     int     endcol = 15;
  2489.     int     newline = TRUE;
  2490.     if (!did_header)
  2491.     {
  2492. msg_putchar('n');
  2493. msg_outtrans(HL_TABLE()[id - 1].sg_name);
  2494.     }
  2495.     else if (msg_col + outlen + 1 >= Columns)
  2496. msg_putchar('n');
  2497.     else
  2498.     {
  2499. if (msg_col >= endcol) /* wrap around is like starting a new line */
  2500.     newline = FALSE;
  2501. msg_putchar(' ');
  2502.     }
  2503.     if (msg_col >= endcol) /* output at least one space */
  2504. endcol = msg_col + 1;
  2505.     if (Columns <= endcol) /* avoid hang for tiny window */
  2506. endcol = Columns - 1;
  2507.     msg_advance(endcol);
  2508.     return newline;
  2509. }
  2510. /*
  2511.  * Set the attribute numbers for a highlight group.
  2512.  * Called after one of the attributes has changed.
  2513.  */
  2514.     static void
  2515. set_hl_attr(idx)
  2516.     int     idx;     /* index in array */
  2517. {
  2518.     struct attr_entry at_en;
  2519.     /* The "Normal" group doesn't need an attribute number */
  2520.     if (STRCMP(HL_TABLE()[idx].sg_name_u, "NORMAL") == 0)
  2521. return;
  2522. #ifdef USE_GUI
  2523.     /*
  2524.      * For the GUI mode: If there are other than "normal" highlighting
  2525.      * attributes, need to allocate an attr number.
  2526.      */
  2527.     if (HL_TABLE()[idx].sg_gui_fg == 0
  2528.     && HL_TABLE()[idx].sg_gui_bg == 0
  2529.     && HL_TABLE()[idx].sg_font == 0)
  2530.     {
  2531. HL_TABLE()[idx].sg_gui_attr = HL_TABLE()[idx].sg_gui;
  2532.     }
  2533.     else
  2534.     {
  2535. at_en.ae_attr = HL_TABLE()[idx].sg_gui;
  2536. at_en.ae_u.gui.fg_color = HL_TABLE()[idx].sg_gui_fg;
  2537. at_en.ae_u.gui.bg_color = HL_TABLE()[idx].sg_gui_bg;
  2538. at_en.ae_u.gui.font = HL_TABLE()[idx].sg_font;
  2539. HL_TABLE()[idx].sg_gui_attr = get_attr_entry(&gui_attr_table, &at_en);
  2540.     }
  2541. #endif
  2542.     /*
  2543.      * For the term mode: If there are other than "normal" highlighting
  2544.      * attributes, need to allocate an attr number.
  2545.      */
  2546.     if (HL_TABLE()[idx].sg_start == NULL && HL_TABLE()[idx].sg_stop == NULL)
  2547. HL_TABLE()[idx].sg_term_attr = HL_TABLE()[idx].sg_term;
  2548.     else
  2549.     {
  2550. at_en.ae_attr = HL_TABLE()[idx].sg_term;
  2551. at_en.ae_u.term.start = HL_TABLE()[idx].sg_start;
  2552. at_en.ae_u.term.stop = HL_TABLE()[idx].sg_stop;
  2553. HL_TABLE()[idx].sg_term_attr = get_attr_entry(&term_attr_table, &at_en);
  2554.     }
  2555.     /*
  2556.      * For the color term mode: If there are other than "normal"
  2557.      * highlighting attributes, need to allocate an attr number.
  2558.      */
  2559.     if (HL_TABLE()[idx].sg_cterm_fg == 0 && HL_TABLE()[idx].sg_cterm_bg == 0)
  2560. HL_TABLE()[idx].sg_cterm_attr = HL_TABLE()[idx].sg_cterm;
  2561.     else
  2562.     {
  2563. at_en.ae_attr = HL_TABLE()[idx].sg_cterm;
  2564. at_en.ae_u.cterm.fg_color = HL_TABLE()[idx].sg_cterm_fg;
  2565. at_en.ae_u.cterm.bg_color = HL_TABLE()[idx].sg_cterm_bg;
  2566. HL_TABLE()[idx].sg_cterm_attr =
  2567.     get_attr_entry(&cterm_attr_table, &at_en);
  2568.     }
  2569. }
  2570. /*
  2571.  * Lookup a highlight group name and return it's ID.
  2572.  * If it is not found, 0 is returned.
  2573.  */
  2574.     int
  2575. syn_name2id(name)
  2576.     char_u *name;
  2577. {
  2578.     int i;
  2579.     char_u *name_u;
  2580.     /* Avoid using stricmp() too much, it's slow on some systems */
  2581.     name_u = vim_strsave_up(name);
  2582.     if (name_u == NULL)
  2583. return 0;
  2584.     for (i = highlight_ga.ga_len; --i >= 0; )
  2585. if (HL_TABLE()[i].sg_name_u != NULL
  2586. && STRCMP(name_u, HL_TABLE()[i].sg_name_u) == 0)
  2587.     break;
  2588.     vim_free(name_u);
  2589.     return i + 1;
  2590. }
  2591. /*
  2592.  * Return TRUE if highlight group "name" exists.
  2593.  */
  2594.     int
  2595. highlight_exists(name)
  2596.     char_u *name;
  2597. {
  2598.     return (syn_name2id(name) > 0);
  2599. }
  2600. /*
  2601.  * Like syn_name2id(), but take a pointer + length argument.
  2602.  */
  2603.     static int
  2604. syn_namen2id(linep, len)
  2605.     char_u  *linep;
  2606.     int     len;
  2607. {
  2608.     char_u  *name;
  2609.     int     id = 0;
  2610.     name = vim_strnsave(linep, len);
  2611.     if (name != NULL)
  2612.     {
  2613. id = syn_name2id(name);
  2614. vim_free(name);
  2615.     }
  2616.     return id;
  2617. }
  2618. /*
  2619.  * Find highlight group name in the table and return it's ID.
  2620.  * The argument is a pointer to the name and the length of the name.
  2621.  * If it doesn't exist yet, a new entry is created.
  2622.  * Return 0 for failure.
  2623.  */
  2624.     int
  2625. syn_check_group(pp, len)
  2626.     char_u *pp;
  2627.     int len;
  2628. {
  2629.     int     id;
  2630.     char_u  *name;
  2631.     name = vim_strnsave(pp, len);
  2632.     if (name == NULL)
  2633. return 0;
  2634.     id = syn_name2id(name);
  2635.     if (id == 0) /* doesn't exist yet */
  2636. id = syn_add_group(name);
  2637.     else
  2638. vim_free(name);
  2639.     return id;
  2640. }
  2641. /*
  2642.  * Add new highlight group and return it's ID.
  2643.  * "name" must be an allocated string, it will be consumed.
  2644.  * Return 0 for failure.
  2645.  */
  2646.     static int
  2647. syn_add_group(name)
  2648.     char_u *name;
  2649. {
  2650.     /*
  2651.      * First call for this growarray: init growing array.
  2652.      */
  2653.     if (highlight_ga.ga_data == NULL)
  2654.     {
  2655. highlight_ga.ga_itemsize = sizeof(struct hl_group);
  2656. highlight_ga.ga_growsize = 10;
  2657.     }
  2658.     /*
  2659.      * Make room for at least one other syntax_highlight entry.
  2660.      */
  2661.     if (ga_grow(&highlight_ga, 1) == FAIL)
  2662.     {
  2663. vim_free(name);
  2664. return 0;
  2665.     }
  2666.     vim_memset(&(HL_TABLE()[highlight_ga.ga_len]), 0, sizeof(struct hl_group));
  2667.     HL_TABLE()[highlight_ga.ga_len].sg_name = name;
  2668.     HL_TABLE()[highlight_ga.ga_len].sg_name_u = vim_strsave_up(name);
  2669.     ++highlight_ga.ga_len;
  2670.     --highlight_ga.ga_room;
  2671.     return highlight_ga.ga_len;     /* ID is index plus one */
  2672. }
  2673. /*
  2674.  * When, just after calling syn_add_group(), an error is discovered, this
  2675.  * function deletes the new name.
  2676.  */
  2677.     static void
  2678. syn_unadd_group()
  2679. {
  2680.     --highlight_ga.ga_len;
  2681.     ++highlight_ga.ga_room;
  2682.     vim_free(HL_TABLE()[highlight_ga.ga_len].sg_name);
  2683.     vim_free(HL_TABLE()[highlight_ga.ga_len].sg_name_u);
  2684. }
  2685. /*
  2686.  * Translate a group ID to highlight attributes.
  2687.  */
  2688.     int
  2689. syn_id2attr(hl_id)
  2690.     int hl_id;
  2691. {
  2692.     int attr;
  2693.     struct hl_group *sgp;
  2694.     hl_id = syn_get_final_id(hl_id);
  2695.     sgp = &HL_TABLE()[hl_id - 1];     /* index is ID minus one */
  2696. #ifdef USE_GUI
  2697.     /*
  2698.      * Only use GUI attr when the GUI is being used.
  2699.      */
  2700.     if (gui.in_use)
  2701. attr = sgp->sg_gui_attr;
  2702.     else
  2703. #endif
  2704. if (*T_CCO)
  2705.     attr = sgp->sg_cterm_attr;
  2706. else
  2707.     attr = sgp->sg_term_attr;
  2708.     return attr;
  2709. }
  2710. #ifdef USE_GUI
  2711. /*
  2712.  * Get the GUI colors and attributes for a group ID.
  2713.  * NOTE: the colors will be 0 when not set, the color plus one otherwise.
  2714.  */
  2715.     int
  2716. syn_id2colors(hl_id, fgp, bgp)
  2717.     int hl_id;
  2718.     GuiColor *fgp;
  2719.     GuiColor *bgp;
  2720. {
  2721.     struct hl_group *sgp;
  2722.     hl_id = syn_get_final_id(hl_id);
  2723.     sgp = &HL_TABLE()[hl_id - 1];     /* index is ID minus one */
  2724.     *fgp = sgp->sg_gui_fg;
  2725.     *bgp = sgp->sg_gui_bg;
  2726.     return sgp->sg_gui;
  2727. }
  2728. #endif
  2729. /*
  2730.  * Translate a group ID to the final group ID (following links).
  2731.  */
  2732.     int
  2733. syn_get_final_id(hl_id)
  2734.     int hl_id;
  2735. {
  2736.     int count;
  2737.     struct hl_group *sgp;
  2738.     if (hl_id > highlight_ga.ga_len || hl_id < 1)
  2739. return 0; /* Can be called from eval!! */
  2740.     /*
  2741.      * Follow links until there is no more.
  2742.      * Look out for loops!  Break after 100 links.
  2743.      */
  2744.     for (count = 100; --count >= 0; )
  2745.     {
  2746. sgp = &HL_TABLE()[hl_id - 1];     /* index is ID minus one */
  2747. if (sgp->sg_link == 0 || sgp->sg_link > highlight_ga.ga_len)
  2748.     break;
  2749. hl_id = sgp->sg_link;
  2750.     }
  2751.     return hl_id;
  2752. }
  2753. #ifdef USE_GUI
  2754. /*
  2755.  * Call this function just after the GUI has started.
  2756.  * It finds the font and color handles for the highlighting groups.
  2757.  */
  2758.     void
  2759. highlight_gui_started()
  2760. {
  2761.     int     idx;
  2762.     /* First get the colors from the "Normal" and "Menu" group, if set */
  2763.     set_normal_colors();
  2764.     for (idx = 0; idx < highlight_ga.ga_len; ++idx)
  2765. gui_do_one_color(idx);
  2766.     highlight_changed();
  2767. }
  2768.     static void
  2769. gui_do_one_color(idx)
  2770.     int     idx;
  2771. {
  2772.     int     didit = FALSE;
  2773.     if (HL_TABLE()[idx].sg_font_name != NULL)
  2774.     {
  2775. HL_TABLE()[idx].sg_font =
  2776.     font_name2handle(HL_TABLE()[idx].sg_font_name);
  2777. didit = TRUE;
  2778.     }
  2779.     if (HL_TABLE()[idx].sg_gui_fg_name != NULL)
  2780.     {
  2781. HL_TABLE()[idx].sg_gui_fg =
  2782.     color_name2handle(HL_TABLE()[idx].sg_gui_fg_name) + 1;
  2783. didit = TRUE;
  2784.     }
  2785.     if (HL_TABLE()[idx].sg_gui_bg_name != NULL)
  2786.     {
  2787. HL_TABLE()[idx].sg_gui_bg =
  2788.     color_name2handle(HL_TABLE()[idx].sg_gui_bg_name) + 1;
  2789. didit = TRUE;
  2790.     }
  2791.     if (didit) /* need to get a new attr number */
  2792. set_hl_attr(idx);
  2793. }
  2794. #endif
  2795. /*
  2796.  * Translate the 'highlight' option into attributes in highlight_attr[].
  2797.  * Called only when the 'highlight' option has been changed.
  2798.  * Return FAIL when an invalid flag is found.  OK otherwise.
  2799.  */
  2800.     int
  2801. highlight_changed()
  2802. {
  2803.     int hlf;
  2804.     int i;
  2805.     char_u *p;
  2806.     int attr;
  2807.     char_u *end;
  2808.     int id;
  2809.     /* Check the HLF_ enums, they must be in the same order! */
  2810.     static int flags[HLF_COUNT] = {'8', '@', 'd', 'e', 'h', 'i', 'l', 'm', 'M',
  2811.    'n', 'r', 's', 'S', 't', 'v', 'w'};
  2812.     need_highlight_changed = FALSE;
  2813.     /*
  2814.      * Clear all attributes.
  2815.      */
  2816.     for (hlf = 0; hlf < (int)HLF_COUNT; ++hlf)
  2817. highlight_attr[hlf] = 0;
  2818.     /*
  2819.      * First set all attributes to their default value.
  2820.      * Then use the attributes from the 'highlight' option.
  2821.      */
  2822.     for (i = 0; i < 2; ++i)
  2823.     {
  2824. if (i)
  2825.     p = p_hl;
  2826. else
  2827.     p = get_highlight_default();
  2828. if (p == NULL)     /* just in case */
  2829.     continue;
  2830. while (*p)
  2831. {
  2832.     for (hlf = 0; hlf < (int)HLF_COUNT; ++hlf)
  2833. if (flags[hlf] == *p)
  2834.     break;
  2835.     ++p;
  2836.     if (hlf == (int)HLF_COUNT || *p == NUL)
  2837. return FAIL;
  2838.     /*
  2839.      * Allow several flags to be combined, like "bu" for
  2840.      * bold-underlined.
  2841.      */
  2842.     attr = 0;
  2843.     for ( ; *p && *p != ','; ++p)     /* parse upto comma */
  2844.     {
  2845. if (vim_iswhite(*p))     /* ignore white space */
  2846.     continue;
  2847. if (attr > HL_ALL)  /* Combination with ':' is not allowed. */
  2848.     return FAIL;
  2849. switch (*p)
  2850. {
  2851.     case 'b': attr |= HL_BOLD;
  2852. break;
  2853.     case 'i': attr |= HL_ITALIC;
  2854. break;
  2855.     case '-':
  2856.     case 'n':     /* no highlighting */
  2857. break;
  2858.     case 'r': attr |= HL_INVERSE;
  2859. break;
  2860.     case 's': attr |= HL_STANDOUT;
  2861. break;
  2862.     case 'u': attr |= HL_UNDERLINE;
  2863. break;
  2864.     case ':': ++p;     /* highlight group name */
  2865. if (attr || *p == NUL)  /* no combinations */
  2866.     return FAIL;
  2867. end = vim_strchr(p, ',');
  2868. if (end == NULL)
  2869.     end = p + STRLEN(p);
  2870. id = syn_check_group(p, (int)(end - p));
  2871. if (id == 0)
  2872.     return FAIL;
  2873. attr = syn_id2attr(id);
  2874. p = end - 1;
  2875. break;
  2876.     default: return FAIL;
  2877. }
  2878.     }
  2879.     highlight_attr[hlf] = attr;
  2880.     p = skip_to_option_part(p);     /* skip comma and spaces */
  2881. }
  2882.     }
  2883.     return OK;
  2884. }
  2885. /*
  2886.  * Handle command line completion for :highlight command.
  2887.  */
  2888.     void
  2889. set_context_in_highlight_cmd(arg)
  2890.     char_u *arg;
  2891. {
  2892.     char_u *p;
  2893.     /* Default: expand group names */
  2894.     expand_context = EXPAND_HIGHLIGHT;
  2895.     expand_pattern = arg;
  2896.     include_link = TRUE;
  2897.     /* (part of) subcommand already typed */
  2898.     if (*arg != NUL)
  2899.     {
  2900. p = skiptowhite(arg);
  2901. if (*p != NUL) /* past group name */
  2902. {
  2903.     include_link = FALSE;
  2904.     if (arg[1] == 'i' && arg[0] == 'N')
  2905. highlight_list();
  2906.     if (STRNCMP("link", arg, p - arg) == 0
  2907.     || STRNCMP("clear", arg, p - arg) == 0)
  2908.     {
  2909. expand_pattern = skipwhite(p);
  2910. p = skiptowhite(expand_pattern);
  2911. if (*p != NUL) /* past first group name */
  2912. {
  2913.     expand_pattern = skipwhite(p);
  2914.     p = skiptowhite(expand_pattern);
  2915. }
  2916.     }
  2917.     if (*p != NUL) /* past group name(s) */
  2918. expand_context = EXPAND_NOTHING;
  2919. }
  2920.     }
  2921. }
  2922. /*
  2923.  * Function given to ExpandGeneric() to obtain the list of group names.
  2924.  * Also used for synIDattr() function.
  2925.  */
  2926.     char_u *
  2927. get_highlight_name(idx)
  2928.     int     idx;
  2929. {
  2930.     if (idx == highlight_ga.ga_len && include_link)
  2931. return (char_u *)"link";
  2932.     if (idx == highlight_ga.ga_len + 1 && include_link)
  2933. return (char_u *)"clear";
  2934.     if (idx < 0 || idx >= highlight_ga.ga_len)
  2935. return NULL;
  2936.     return HL_TABLE()[idx].sg_name;
  2937. }
  2938. #ifdef USE_GUI
  2939. /*
  2940.  * Free all the highlight group fonts.
  2941.  * Used when quitting for systems which need it.
  2942.  */
  2943.     void
  2944. free_highlight_fonts()
  2945. {
  2946.     int     idx;
  2947.     for (idx = 0; idx < highlight_ga.ga_len; ++idx)
  2948.     {
  2949. gui_mch_free_font(HL_TABLE()[idx].sg_font);
  2950. HL_TABLE()[idx].sg_font = 0;
  2951.     }
  2952.     gui_mch_free_font(gui.norm_font);
  2953.     gui_mch_free_font(gui.bold_font);
  2954.     gui_mch_free_font(gui.ital_font);
  2955.     gui_mch_free_font(gui.boldital_font);
  2956. }
  2957. #endif
  2958. /**************************************
  2959.  *  End of Highlighting stuff       *
  2960.  **************************************/