2001-05-05 19:01:42 +04:00
|
|
|
/**************************************************************************
|
2016-08-29 18:10:49 +03:00
|
|
|
* color.c -- This file is part of GNU nano. *
|
2001-05-05 19:01:42 +04:00
|
|
|
* *
|
2017-04-09 13:09:23 +03:00
|
|
|
* Copyright (C) 2001-2011, 2013-2017 Free Software Foundation, Inc. *
|
2017-02-21 22:27:49 +03:00
|
|
|
* Copyright (C) 2014, 2015, 2016, 2017 Benno Schulenberg *
|
2016-08-29 16:14:18 +03:00
|
|
|
* *
|
2016-08-29 18:10:49 +03:00
|
|
|
* GNU nano is free software: you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published *
|
|
|
|
* by the Free Software Foundation, either version 3 of the License, *
|
|
|
|
* or (at your option) any later version. *
|
2001-05-05 19:01:42 +04:00
|
|
|
* *
|
2016-08-29 18:10:49 +03:00
|
|
|
* GNU nano is distributed in the hope that it will be useful, *
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty *
|
|
|
|
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
|
|
* See the GNU General Public License for more details. *
|
2001-05-05 19:01:42 +04:00
|
|
|
* *
|
|
|
|
* You should have received a copy of the GNU General Public License *
|
2016-08-29 18:10:49 +03:00
|
|
|
* along with this program. If not, see http://www.gnu.org/licenses/. *
|
2001-05-05 19:01:42 +04:00
|
|
|
* *
|
|
|
|
**************************************************************************/
|
|
|
|
|
2005-12-08 05:47:10 +03:00
|
|
|
#include "proto.h"
|
2001-05-05 19:01:42 +04:00
|
|
|
|
2011-02-13 07:23:10 +03:00
|
|
|
#include <errno.h>
|
|
|
|
#ifdef HAVE_MAGIC_H
|
|
|
|
#include <magic.h>
|
|
|
|
#endif
|
2017-08-06 14:32:44 +03:00
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
2001-05-05 19:01:42 +04:00
|
|
|
|
2014-04-04 15:59:03 +04:00
|
|
|
#ifndef DISABLE_COLOR
|
2002-07-19 05:08:59 +04:00
|
|
|
|
2015-12-18 21:44:40 +03:00
|
|
|
/* Initialize the colors for nano's interface, and assign pair numbers
|
|
|
|
* for the colors in each syntax. */
|
2002-09-27 18:21:59 +04:00
|
|
|
void set_colorpairs(void)
|
2001-05-05 19:01:42 +04:00
|
|
|
{
|
2016-07-25 11:53:49 +03:00
|
|
|
const syntaxtype *sint;
|
2015-12-18 21:44:40 +03:00
|
|
|
bool using_defaults = FALSE;
|
|
|
|
short foreground, background;
|
2014-05-03 22:24:45 +04:00
|
|
|
size_t i;
|
|
|
|
|
2015-12-18 21:44:40 +03:00
|
|
|
/* Tell ncurses to enable colors. */
|
2014-05-03 22:24:45 +04:00
|
|
|
start_color();
|
|
|
|
|
|
|
|
#ifdef HAVE_USE_DEFAULT_COLORS
|
2015-12-18 21:44:40 +03:00
|
|
|
/* Allow using the default colors, if available. */
|
|
|
|
using_defaults = (use_default_colors() != ERR);
|
2014-05-03 22:24:45 +04:00
|
|
|
#endif
|
|
|
|
|
2015-12-18 21:44:40 +03:00
|
|
|
/* Initialize the color pairs for nano's interface elements. */
|
2014-05-03 22:24:45 +04:00
|
|
|
for (i = 0; i < NUMBER_OF_ELEMENTS; i++) {
|
2014-05-10 23:15:04 +04:00
|
|
|
bool bright = FALSE;
|
|
|
|
|
2017-07-07 12:48:26 +03:00
|
|
|
if (specified_color_combo[i] != NULL &&
|
|
|
|
parse_color_names(specified_color_combo[i],
|
|
|
|
&foreground, &background, &bright)) {
|
2015-12-18 21:44:40 +03:00
|
|
|
if (foreground == -1 && !using_defaults)
|
|
|
|
foreground = COLOR_WHITE;
|
|
|
|
if (background == -1 && !using_defaults)
|
|
|
|
background = COLOR_BLACK;
|
|
|
|
init_pair(i + 1, foreground, background);
|
2016-07-12 10:35:48 +03:00
|
|
|
interface_color_pair[i] =
|
2016-07-11 23:25:56 +03:00
|
|
|
COLOR_PAIR(i + 1) | (bright ? A_BOLD : A_NORMAL);
|
2017-07-07 12:48:26 +03:00
|
|
|
} else {
|
2014-05-10 23:15:04 +04:00
|
|
|
if (i != FUNCTION_TAG)
|
2016-07-12 10:35:48 +03:00
|
|
|
interface_color_pair[i] = hilite_attribute;
|
2014-05-10 23:15:04 +04:00
|
|
|
else
|
2016-07-12 10:35:48 +03:00
|
|
|
interface_color_pair[i] = A_NORMAL;
|
2014-05-03 22:24:45 +04:00
|
|
|
}
|
|
|
|
|
2015-06-14 22:14:41 +03:00
|
|
|
free(specified_color_combo[i]);
|
|
|
|
specified_color_combo[i] = NULL;
|
2014-05-03 22:24:45 +04:00
|
|
|
}
|
2002-09-27 18:21:59 +04:00
|
|
|
|
2015-12-18 21:44:40 +03:00
|
|
|
/* For each syntax, go through its list of colors and assign each
|
|
|
|
* its pair number, giving identical color pairs the same number. */
|
2016-07-25 11:53:49 +03:00
|
|
|
for (sint = syntaxes; sint != NULL; sint = sint->next) {
|
|
|
|
colortype *ink;
|
2016-07-25 11:57:33 +03:00
|
|
|
int new_number = NUMBER_OF_ELEMENTS + 1;
|
2002-09-27 18:21:59 +04:00
|
|
|
|
2016-07-25 11:53:49 +03:00
|
|
|
for (ink = sint->color; ink != NULL; ink = ink->next) {
|
|
|
|
const colortype *beforenow = sint->color;
|
2002-09-27 18:21:59 +04:00
|
|
|
|
2016-07-25 11:53:49 +03:00
|
|
|
while (beforenow != ink && (beforenow->fg != ink->fg ||
|
|
|
|
beforenow->bg != ink->bg ||
|
|
|
|
beforenow->bright != ink->bright))
|
2015-12-18 21:44:40 +03:00
|
|
|
beforenow = beforenow->next;
|
2002-09-27 18:21:59 +04:00
|
|
|
|
2016-07-25 11:53:49 +03:00
|
|
|
if (beforenow != ink)
|
|
|
|
ink->pairnum = beforenow->pairnum;
|
2016-07-25 11:57:33 +03:00
|
|
|
else
|
|
|
|
ink->pairnum = new_number++;
|
2016-07-17 16:29:07 +03:00
|
|
|
|
2016-07-25 11:53:49 +03:00
|
|
|
ink->attributes = COLOR_PAIR(ink->pairnum) |
|
|
|
|
(ink->bright ? A_BOLD : A_NORMAL);
|
2002-09-27 18:21:59 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2001-11-29 05:42:27 +03:00
|
|
|
|
2005-07-15 04:36:49 +04:00
|
|
|
/* Initialize the color information. */
|
2005-07-14 00:18:46 +04:00
|
|
|
void color_init(void)
|
2002-09-27 18:21:59 +04:00
|
|
|
{
|
2016-07-04 14:43:19 +03:00
|
|
|
const colortype *ink;
|
2015-12-18 13:41:09 +03:00
|
|
|
bool using_defaults = FALSE;
|
|
|
|
short foreground, background;
|
|
|
|
|
|
|
|
/* If the terminal is not capable of colors, forget it. */
|
|
|
|
if (!has_colors())
|
|
|
|
return;
|
|
|
|
|
2001-05-05 19:01:42 +04:00
|
|
|
#ifdef HAVE_USE_DEFAULT_COLORS
|
2015-12-18 13:41:09 +03:00
|
|
|
/* Allow using the default colors, if available. */
|
|
|
|
using_defaults = (use_default_colors() != ERR);
|
2001-05-05 19:01:42 +04:00
|
|
|
#endif
|
2001-11-29 05:42:27 +03:00
|
|
|
|
2015-12-18 13:45:35 +03:00
|
|
|
/* For each coloring expression, initialize the color pair. */
|
2016-07-04 14:43:19 +03:00
|
|
|
for (ink = openfile->colorstrings; ink != NULL; ink = ink->next) {
|
|
|
|
foreground = ink->fg;
|
|
|
|
background = ink->bg;
|
2015-12-18 13:41:09 +03:00
|
|
|
|
2015-12-18 13:45:35 +03:00
|
|
|
if (foreground == -1 && !using_defaults)
|
|
|
|
foreground = COLOR_WHITE;
|
2001-11-29 05:42:27 +03:00
|
|
|
|
2015-12-18 13:45:35 +03:00
|
|
|
if (background == -1 && !using_defaults)
|
|
|
|
background = COLOR_BLACK;
|
2001-11-29 05:42:27 +03:00
|
|
|
|
2016-07-04 14:43:19 +03:00
|
|
|
init_pair(ink->pairnum, foreground, background);
|
2015-12-18 13:45:35 +03:00
|
|
|
}
|
2017-04-27 22:42:36 +03:00
|
|
|
|
|
|
|
have_palette = TRUE;
|
2001-05-05 19:01:42 +04:00
|
|
|
}
|
|
|
|
|
2016-02-26 19:37:23 +03:00
|
|
|
/* Try to match the given shibboleth string with one of the regexes in
|
|
|
|
* the list starting at head. Return TRUE upon success. */
|
|
|
|
bool found_in_list(regexlisttype *head, const char *shibboleth)
|
|
|
|
{
|
|
|
|
regexlisttype *item;
|
2016-03-04 17:53:45 +03:00
|
|
|
regex_t rgx;
|
2016-02-26 19:37:23 +03:00
|
|
|
|
|
|
|
for (item = head; item != NULL; item = item->next) {
|
2016-03-22 13:42:28 +03:00
|
|
|
regcomp(&rgx, fixbounds(item->full_regex), NANO_REG_EXTENDED);
|
2016-02-26 19:37:23 +03:00
|
|
|
|
2016-03-04 17:53:45 +03:00
|
|
|
if (regexec(&rgx, shibboleth, 0, NULL, 0) == 0) {
|
|
|
|
regfree(&rgx);
|
2016-02-26 19:37:23 +03:00
|
|
|
return TRUE;
|
2016-02-26 20:25:48 +03:00
|
|
|
}
|
2016-03-04 17:53:45 +03:00
|
|
|
|
|
|
|
regfree(&rgx);
|
2016-02-26 19:37:23 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2016-03-12 12:18:50 +03:00
|
|
|
/* Update the color information based on the current filename and content. */
|
2005-07-14 00:18:46 +04:00
|
|
|
void color_update(void)
|
2002-05-04 07:47:33 +04:00
|
|
|
{
|
2016-03-12 11:46:18 +03:00
|
|
|
syntaxtype *sint = NULL;
|
2016-03-04 23:50:38 +03:00
|
|
|
colortype *ink;
|
2011-02-13 07:23:10 +03:00
|
|
|
|
2014-06-30 21:47:07 +04:00
|
|
|
/* If the rcfiles were not read, or contained no syntaxes, get out. */
|
|
|
|
if (syntaxes == NULL)
|
|
|
|
return;
|
|
|
|
|
2016-03-12 12:18:50 +03:00
|
|
|
/* If we specified a syntax-override string, use it. */
|
2005-07-31 01:24:56 +04:00
|
|
|
if (syntaxstr != NULL) {
|
2016-03-12 12:18:50 +03:00
|
|
|
/* An override of "none" is like having no syntax at all. */
|
2005-08-01 08:59:34 +04:00
|
|
|
if (strcmp(syntaxstr, "none") == 0)
|
|
|
|
return;
|
|
|
|
|
2016-02-26 20:11:35 +03:00
|
|
|
for (sint = syntaxes; sint != NULL; sint = sint->next) {
|
2016-03-12 11:46:18 +03:00
|
|
|
if (strcmp(sint->name, syntaxstr) == 0)
|
2016-03-10 23:06:01 +03:00
|
|
|
break;
|
2002-05-04 07:47:33 +04:00
|
|
|
}
|
2015-11-24 14:42:19 +03:00
|
|
|
|
2017-10-12 20:06:39 +03:00
|
|
|
if (sint == NULL && !inhelp)
|
2016-04-30 18:31:43 +03:00
|
|
|
statusline(ALERT, _("Unknown syntax name: %s"), syntaxstr);
|
2002-05-04 07:47:33 +04:00
|
|
|
}
|
2002-05-04 08:23:30 +04:00
|
|
|
|
2016-03-12 12:18:50 +03:00
|
|
|
/* If no syntax-override string was specified, or it didn't match,
|
|
|
|
* try finding a syntax based on the filename (extension). */
|
2017-10-12 20:06:39 +03:00
|
|
|
if (sint == NULL && !inhelp) {
|
2016-06-04 13:02:49 +03:00
|
|
|
char *reserved = charalloc(PATH_MAX + 1);
|
|
|
|
char *currentdir = getcwd(reserved, PATH_MAX + 1);
|
2015-04-28 22:18:38 +03:00
|
|
|
char *joinednames = charalloc(PATH_MAX + 1);
|
|
|
|
char *fullname = NULL;
|
|
|
|
|
2016-06-04 13:02:49 +03:00
|
|
|
if (currentdir == NULL)
|
|
|
|
free(reserved);
|
|
|
|
else {
|
2015-04-28 22:18:38 +03:00
|
|
|
/* Concatenate the current working directory with the
|
|
|
|
* specified filename, and canonicalize the result. */
|
|
|
|
sprintf(joinednames, "%s/%s", currentdir, openfile->filename);
|
2016-02-29 19:56:54 +03:00
|
|
|
fullname = get_full_path(joinednames);
|
2015-04-28 22:18:38 +03:00
|
|
|
free(currentdir);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fullname == NULL)
|
|
|
|
fullname = mallocstrcpy(fullname, openfile->filename);
|
|
|
|
|
2016-02-26 20:11:35 +03:00
|
|
|
for (sint = syntaxes; sint != NULL; sint = sint->next) {
|
2016-03-12 11:46:18 +03:00
|
|
|
if (found_in_list(sint->extensions, fullname))
|
2016-03-10 23:06:01 +03:00
|
|
|
break;
|
2011-02-13 07:23:10 +03:00
|
|
|
}
|
|
|
|
|
2015-04-28 22:18:38 +03:00
|
|
|
free(joinednames);
|
|
|
|
free(fullname);
|
2016-03-12 12:18:50 +03:00
|
|
|
}
|
2015-04-28 22:18:38 +03:00
|
|
|
|
2016-03-12 12:18:50 +03:00
|
|
|
/* If the filename didn't match anything, try the first line. */
|
2017-10-12 20:06:39 +03:00
|
|
|
if (sint == NULL && !inhelp) {
|
2016-03-12 12:18:50 +03:00
|
|
|
for (sint = syntaxes; sint != NULL; sint = sint->next) {
|
|
|
|
if (found_in_list(sint->headers, openfile->fileage->data))
|
|
|
|
break;
|
2005-07-14 00:18:46 +04:00
|
|
|
}
|
2016-03-12 12:18:50 +03:00
|
|
|
}
|
2008-09-22 03:02:30 +04:00
|
|
|
|
2014-05-14 14:09:42 +04:00
|
|
|
#ifdef HAVE_LIBMAGIC
|
2016-03-12 12:18:50 +03:00
|
|
|
/* If we still don't have an answer, try using magic. */
|
2017-10-12 20:06:39 +03:00
|
|
|
if (sint == NULL && !inhelp) {
|
2016-03-12 12:18:50 +03:00
|
|
|
struct stat fileinfo;
|
|
|
|
magic_t cookie = NULL;
|
|
|
|
const char *magicstring = NULL;
|
2017-09-14 22:57:12 +03:00
|
|
|
|
2016-03-12 12:18:50 +03:00
|
|
|
if (stat(openfile->filename, &fileinfo) == 0) {
|
|
|
|
/* Open the magic database and get a diagnosis of the file. */
|
|
|
|
cookie = magic_open(MAGIC_SYMLINK |
|
2014-05-14 14:29:55 +04:00
|
|
|
#ifdef DEBUG
|
2015-03-27 16:46:50 +03:00
|
|
|
MAGIC_DEBUG | MAGIC_CHECK |
|
2014-05-14 14:29:55 +04:00
|
|
|
#endif
|
2015-03-27 16:46:50 +03:00
|
|
|
MAGIC_ERROR);
|
2016-03-12 12:18:50 +03:00
|
|
|
if (cookie == NULL || magic_load(cookie, NULL) < 0)
|
2016-04-30 18:31:43 +03:00
|
|
|
statusline(ALERT, _("magic_load() failed: %s"), strerror(errno));
|
2016-03-12 12:18:50 +03:00
|
|
|
else {
|
|
|
|
magicstring = magic_file(cookie, openfile->filename);
|
|
|
|
if (magicstring == NULL)
|
2016-04-30 18:31:43 +03:00
|
|
|
statusline(ALERT, _("magic_file(%s) failed: %s"),
|
2016-03-12 12:18:50 +03:00
|
|
|
openfile->filename, magic_error(cookie));
|
2014-05-14 14:29:55 +04:00
|
|
|
}
|
2016-03-12 12:18:50 +03:00
|
|
|
}
|
2014-05-14 14:29:55 +04:00
|
|
|
|
2016-03-12 12:18:50 +03:00
|
|
|
/* Now try and find a syntax that matches the magic string. */
|
|
|
|
if (magicstring != NULL) {
|
|
|
|
for (sint = syntaxes; sint != NULL; sint = sint->next) {
|
2016-05-17 12:33:21 +03:00
|
|
|
if (found_in_list(sint->magics, magicstring))
|
2016-03-12 12:18:50 +03:00
|
|
|
break;
|
2008-09-22 03:02:30 +04:00
|
|
|
}
|
|
|
|
}
|
2016-03-12 12:18:50 +03:00
|
|
|
|
|
|
|
if (stat(openfile->filename, &fileinfo) == 0)
|
|
|
|
magic_close(cookie);
|
2005-07-14 00:18:46 +04:00
|
|
|
}
|
2016-03-12 12:18:50 +03:00
|
|
|
#endif /* HAVE_LIBMAGIC */
|
2005-07-14 00:18:46 +04:00
|
|
|
|
2016-03-12 12:18:50 +03:00
|
|
|
/* If nothing at all matched, see if there is a default syntax. */
|
2017-10-12 20:06:39 +03:00
|
|
|
if (sint == NULL && !inhelp) {
|
2016-02-26 20:11:35 +03:00
|
|
|
for (sint = syntaxes; sint != NULL; sint = sint->next) {
|
2016-03-12 11:46:18 +03:00
|
|
|
if (strcmp(sint->name, "default") == 0)
|
2016-03-10 23:06:01 +03:00
|
|
|
break;
|
2016-02-26 19:08:21 +03:00
|
|
|
}
|
2009-01-25 10:25:17 +03:00
|
|
|
}
|
2005-08-01 08:23:29 +04:00
|
|
|
|
2016-03-12 11:46:18 +03:00
|
|
|
openfile->syntax = sint;
|
|
|
|
openfile->colorstrings = (sint == NULL ? NULL : sint->color);
|
|
|
|
|
2016-03-12 12:18:50 +03:00
|
|
|
/* If a syntax was found, compile its specified regexes (which have
|
|
|
|
* already been checked for validity when they were read in). */
|
2016-03-14 19:01:44 +03:00
|
|
|
for (ink = openfile->colorstrings; ink != NULL; ink = ink->next) {
|
2016-03-04 23:50:38 +03:00
|
|
|
if (ink->start == NULL) {
|
|
|
|
ink->start = (regex_t *)nmalloc(sizeof(regex_t));
|
2016-03-13 22:37:21 +03:00
|
|
|
regcomp(ink->start, fixbounds(ink->start_regex), ink->rex_flags);
|
2005-07-14 00:18:46 +04:00
|
|
|
}
|
2005-07-14 22:33:51 +04:00
|
|
|
|
2016-03-04 23:50:38 +03:00
|
|
|
if (ink->end_regex != NULL && ink->end == NULL) {
|
|
|
|
ink->end = (regex_t *)nmalloc(sizeof(regex_t));
|
2016-03-13 22:37:21 +03:00
|
|
|
regcomp(ink->end, fixbounds(ink->end_regex), ink->rex_flags);
|
2002-05-04 08:23:30 +04:00
|
|
|
}
|
|
|
|
}
|
2002-05-04 07:47:33 +04:00
|
|
|
}
|
|
|
|
|
2017-02-12 22:49:40 +03:00
|
|
|
/* Determine whether the matches of multiline regexes are still the same,
|
|
|
|
* and if not, schedule a screen refresh, so things will be repainted. */
|
2017-02-13 21:11:04 +03:00
|
|
|
void check_the_multis(filestruct *line)
|
2009-02-06 06:41:02 +03:00
|
|
|
{
|
2016-07-04 14:43:19 +03:00
|
|
|
const colortype *ink;
|
2017-02-14 18:56:43 +03:00
|
|
|
bool astart, anend;
|
2009-02-06 06:41:02 +03:00
|
|
|
regmatch_t startmatch, endmatch;
|
2009-01-25 10:25:17 +03:00
|
|
|
|
2016-01-03 19:57:17 +03:00
|
|
|
/* If there is no syntax or no multiline regex, there is nothing to do. */
|
|
|
|
if (openfile->syntax == NULL || openfile->syntax->nmultis == 0)
|
2009-01-30 11:34:27 +03:00
|
|
|
return;
|
|
|
|
|
2016-07-04 14:43:19 +03:00
|
|
|
for (ink = openfile->colorstrings; ink != NULL; ink = ink->next) {
|
2017-02-13 21:31:36 +03:00
|
|
|
/* If it's not a multiline regex, skip. */
|
2016-07-04 14:43:19 +03:00
|
|
|
if (ink->end == NULL)
|
2009-02-06 06:41:02 +03:00
|
|
|
continue;
|
|
|
|
|
2017-02-13 21:11:04 +03:00
|
|
|
alloc_multidata_if_needed(line);
|
2009-02-17 00:04:00 +03:00
|
|
|
|
2017-02-14 18:56:43 +03:00
|
|
|
astart = (regexec(ink->start, line->data, 1, &startmatch, 0) == 0);
|
|
|
|
anend = (regexec(ink->end, line->data, 1, &endmatch, 0) == 0);
|
2017-02-13 21:25:14 +03:00
|
|
|
|
2017-02-13 21:31:36 +03:00
|
|
|
/* Check whether the multidata still matches the current situation. */
|
|
|
|
if (line->multidata[ink->id] == CNONE ||
|
2017-02-13 21:11:04 +03:00
|
|
|
line->multidata[ink->id] == CWHOLELINE) {
|
2017-02-13 21:31:36 +03:00
|
|
|
if (!astart && !anend)
|
|
|
|
continue;
|
|
|
|
} else if (line->multidata[ink->id] == CSTARTENDHERE) {
|
|
|
|
if (astart && anend && startmatch.rm_so < endmatch.rm_so)
|
|
|
|
continue;
|
|
|
|
} else if (line->multidata[ink->id] == CBEGINBEFORE) {
|
|
|
|
if (!astart && anend)
|
|
|
|
continue;
|
|
|
|
} else if (line->multidata[ink->id] == CENDAFTER) {
|
|
|
|
if (astart && !anend)
|
|
|
|
continue;
|
|
|
|
}
|
2009-02-06 06:41:02 +03:00
|
|
|
|
2017-02-13 21:31:36 +03:00
|
|
|
/* There is a mismatch, so something changed: repaint. */
|
2017-01-23 16:41:25 +03:00
|
|
|
refresh_needed = TRUE;
|
|
|
|
return;
|
2009-01-25 10:25:17 +03:00
|
|
|
}
|
|
|
|
}
|
2014-04-04 15:59:03 +04:00
|
|
|
|
2015-12-22 19:51:00 +03:00
|
|
|
/* Allocate (for one line) the cache space for multiline color regexes. */
|
|
|
|
void alloc_multidata_if_needed(filestruct *fileptr)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (fileptr->multidata == NULL) {
|
|
|
|
fileptr->multidata = (short *)nmalloc(openfile->syntax->nmultis * sizeof(short));
|
|
|
|
|
|
|
|
for (i = 0; i < openfile->syntax->nmultis; i++)
|
|
|
|
fileptr->multidata[i] = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Precalculate the multi-line start and end regex info so we can
|
|
|
|
* speed up rendering (with any hope at all...). */
|
|
|
|
void precalc_multicolorinfo(void)
|
|
|
|
{
|
2016-07-04 14:43:19 +03:00
|
|
|
const colortype *ink;
|
2015-12-22 19:51:00 +03:00
|
|
|
regmatch_t startmatch, endmatch;
|
2017-01-21 20:03:19 +03:00
|
|
|
filestruct *line, *tailline;
|
2015-12-22 19:51:00 +03:00
|
|
|
|
|
|
|
if (openfile->colorstrings == NULL || ISSET(NO_COLOR_SYNTAX))
|
|
|
|
return;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
2017-01-21 18:17:43 +03:00
|
|
|
fprintf(stderr, "Precalculating the multiline color info...\n");
|
2015-12-22 19:51:00 +03:00
|
|
|
#endif
|
|
|
|
|
2016-07-04 14:43:19 +03:00
|
|
|
for (ink = openfile->colorstrings; ink != NULL; ink = ink->next) {
|
2015-12-22 19:51:00 +03:00
|
|
|
/* If this is not a multi-line regex, skip it. */
|
2016-07-04 14:43:19 +03:00
|
|
|
if (ink->end == NULL)
|
2015-12-22 19:51:00 +03:00
|
|
|
continue;
|
|
|
|
|
2017-01-21 19:53:00 +03:00
|
|
|
for (line = openfile->fileage; line != NULL; line = line->next) {
|
2017-01-21 19:38:21 +03:00
|
|
|
int index = 0;
|
2017-01-21 18:17:43 +03:00
|
|
|
|
2017-01-21 19:53:00 +03:00
|
|
|
alloc_multidata_if_needed(line);
|
2017-01-21 18:50:52 +03:00
|
|
|
/* Assume nothing applies until proven otherwise below. */
|
2017-01-21 19:53:00 +03:00
|
|
|
line->multidata[ink->id] = CNONE;
|
2015-12-22 19:51:00 +03:00
|
|
|
|
2017-02-13 00:34:31 +03:00
|
|
|
/* For an unpaired start match, mark all remaining lines. */
|
|
|
|
if (line->prev && line->prev->multidata[ink->id] == CWOULDBE) {
|
|
|
|
line->multidata[ink->id] = CWOULDBE;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-01-21 19:36:52 +03:00
|
|
|
/* When the line contains a start match, look for an end, and if
|
|
|
|
* found, mark all the lines that are affected. */
|
2017-01-21 19:53:00 +03:00
|
|
|
while (regexec(ink->start, line->data + index, 1,
|
2017-01-21 19:38:21 +03:00
|
|
|
&startmatch, (index == 0) ? 0 : REG_NOTBOL) == 0) {
|
2017-01-21 20:18:34 +03:00
|
|
|
/* Begin looking for an end match after the start match. */
|
2017-01-21 19:38:21 +03:00
|
|
|
index += startmatch.rm_eo;
|
2017-01-18 21:53:51 +03:00
|
|
|
|
2017-01-21 19:36:52 +03:00
|
|
|
/* If there is an end match on this line, mark the line, but
|
|
|
|
* continue looking for other starts after it. */
|
2017-01-21 19:53:00 +03:00
|
|
|
if (regexec(ink->end, line->data + index, 1,
|
2017-01-21 19:38:21 +03:00
|
|
|
&endmatch, (index == 0) ? 0 : REG_NOTBOL) == 0) {
|
2017-01-21 19:53:00 +03:00
|
|
|
line->multidata[ink->id] = CSTARTENDHERE;
|
2017-01-21 19:38:21 +03:00
|
|
|
index += endmatch.rm_eo;
|
2017-01-21 19:36:52 +03:00
|
|
|
/* If both start and end are mere anchors, step ahead. */
|
2016-01-09 21:41:56 +03:00
|
|
|
if (startmatch.rm_so == startmatch.rm_eo &&
|
2017-01-21 20:18:34 +03:00
|
|
|
endmatch.rm_so == endmatch.rm_eo) {
|
|
|
|
/* When at end-of-line, we're done. */
|
|
|
|
if (line->data[index] == '\0')
|
|
|
|
break;
|
|
|
|
index = move_mbright(line->data, index);
|
|
|
|
}
|
2015-12-22 19:51:00 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-01-21 19:36:52 +03:00
|
|
|
/* Look for an end match on later lines. */
|
2017-01-21 20:03:19 +03:00
|
|
|
tailline = line->next;
|
2017-01-21 19:36:52 +03:00
|
|
|
|
2017-01-21 20:03:19 +03:00
|
|
|
while (tailline != NULL) {
|
|
|
|
if (regexec(ink->end, tailline->data, 1, &endmatch, 0) == 0)
|
2015-12-22 19:51:00 +03:00
|
|
|
break;
|
2017-01-21 20:03:19 +03:00
|
|
|
tailline = tailline->next;
|
2015-12-22 19:51:00 +03:00
|
|
|
}
|
|
|
|
|
2017-02-13 00:34:31 +03:00
|
|
|
if (tailline == NULL) {
|
|
|
|
line->multidata[ink->id] = CWOULDBE;
|
2015-12-22 19:51:00 +03:00
|
|
|
break;
|
2017-02-13 00:34:31 +03:00
|
|
|
}
|
2017-01-21 18:17:43 +03:00
|
|
|
|
2015-12-22 19:51:00 +03:00
|
|
|
/* We found it, we found it, la la la la la. Mark all
|
|
|
|
* the lines in between and the end properly. */
|
2017-01-21 19:53:00 +03:00
|
|
|
line->multidata[ink->id] = CENDAFTER;
|
2017-01-21 18:17:43 +03:00
|
|
|
|
2017-01-21 20:03:19 +03:00
|
|
|
for (line = line->next; line != tailline; line = line->next) {
|
2017-01-21 19:53:00 +03:00
|
|
|
alloc_multidata_if_needed(line);
|
|
|
|
line->multidata[ink->id] = CWHOLELINE;
|
2015-12-22 19:51:00 +03:00
|
|
|
}
|
|
|
|
|
2017-01-21 20:03:19 +03:00
|
|
|
alloc_multidata_if_needed(tailline);
|
|
|
|
tailline->multidata[ink->id] = CBEGINBEFORE;
|
2017-01-21 18:17:43 +03:00
|
|
|
|
2017-01-21 19:36:52 +03:00
|
|
|
/* Begin looking for a new start after the end match. */
|
2017-01-21 19:38:21 +03:00
|
|
|
index = endmatch.rm_eo;
|
2015-12-22 19:51:00 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-04 15:59:03 +04:00
|
|
|
#endif /* !DISABLE_COLOR */
|