2001-05-05 19:01:42 +04:00
|
|
|
/* $Id$ */
|
|
|
|
/**************************************************************************
|
|
|
|
* color.c *
|
|
|
|
* *
|
2014-05-01 00:18:26 +04:00
|
|
|
* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, *
|
2015-04-28 22:18:38 +03:00
|
|
|
* 2010, 2011, 2013, 2014, 2015 Free Software Foundation, Inc. *
|
2001-05-05 19:01:42 +04:00
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
2007-08-11 09:17:36 +04:00
|
|
|
* the Free Software Foundation; either version 3, or (at your option) *
|
2001-05-05 19:01:42 +04:00
|
|
|
* any later version. *
|
|
|
|
* *
|
2005-05-15 23:57:17 +04:00
|
|
|
* This program is distributed in the hope that it will be useful, but *
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
|
|
|
* General Public License for more details. *
|
2001-05-05 19:01:42 +04:00
|
|
|
* *
|
|
|
|
* You should have received a copy of the GNU General Public License *
|
|
|
|
* along with this program; if not, write to the Free Software *
|
2005-05-15 23:57:17 +04:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
|
|
|
|
* 02110-1301, USA. *
|
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
|
|
|
|
|
|
|
#include <stdio.h>
|
2005-08-01 08:34:27 +04:00
|
|
|
#include <string.h>
|
2011-02-13 07:23:10 +03:00
|
|
|
#include <errno.h>
|
2015-12-22 19:51:00 +03:00
|
|
|
#include <time.h>
|
2015-04-28 22:18:38 +03:00
|
|
|
#include <unistd.h>
|
2011-02-13 07:23:10 +03:00
|
|
|
|
|
|
|
#ifdef HAVE_MAGIC_H
|
|
|
|
#include <magic.h>
|
|
|
|
#endif
|
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
|
|
|
{
|
2002-09-27 18:21:59 +04:00
|
|
|
const syntaxtype *this_syntax = syntaxes;
|
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;
|
|
|
|
|
2015-12-18 21:44:40 +03:00
|
|
|
if (parse_color_names(specified_color_combo[i],
|
|
|
|
&foreground, &background, &bright)) {
|
|
|
|
if (foreground == -1 && !using_defaults)
|
|
|
|
foreground = COLOR_WHITE;
|
|
|
|
if (background == -1 && !using_defaults)
|
|
|
|
background = COLOR_BLACK;
|
|
|
|
init_pair(i + 1, foreground, background);
|
2014-05-10 23:15:04 +04:00
|
|
|
interface_color_pair[i].bright = bright;
|
|
|
|
interface_color_pair[i].pairnum = COLOR_PAIR(i + 1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
interface_color_pair[i].bright = FALSE;
|
|
|
|
if (i != FUNCTION_TAG)
|
|
|
|
interface_color_pair[i].pairnum = hilite_attribute;
|
|
|
|
else
|
|
|
|
interface_color_pair[i].pairnum = 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. */
|
2003-11-06 01:04:08 +03:00
|
|
|
for (; this_syntax != NULL; this_syntax = this_syntax->next) {
|
2002-09-27 18:21:59 +04:00
|
|
|
colortype *this_color = this_syntax->color;
|
2014-05-10 23:15:04 +04:00
|
|
|
int clr_pair = NUMBER_OF_ELEMENTS + 1;
|
2002-09-27 18:21:59 +04:00
|
|
|
|
2003-11-06 01:04:08 +03:00
|
|
|
for (; this_color != NULL; this_color = this_color->next) {
|
2002-09-27 18:21:59 +04:00
|
|
|
const colortype *beforenow = this_syntax->color;
|
|
|
|
|
2015-12-18 21:44:40 +03:00
|
|
|
while (beforenow != this_color &&
|
|
|
|
(beforenow->fg != this_color->fg ||
|
|
|
|
beforenow->bg != this_color->bg ||
|
|
|
|
beforenow->bright != this_color->bright))
|
|
|
|
beforenow = beforenow->next;
|
2002-09-27 18:21:59 +04:00
|
|
|
|
2005-03-10 23:55:11 +03:00
|
|
|
if (beforenow != this_color)
|
2002-09-27 18:21:59 +04:00
|
|
|
this_color->pairnum = beforenow->pairnum;
|
|
|
|
else {
|
2014-05-10 23:15:04 +04:00
|
|
|
this_color->pairnum = clr_pair;
|
|
|
|
clr_pair++;
|
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
|
|
|
{
|
2015-12-18 13:41:09 +03:00
|
|
|
colortype *tmpcolor = openfile->colorstrings;
|
|
|
|
bool using_defaults = FALSE;
|
|
|
|
short foreground, background;
|
|
|
|
|
2005-07-14 00:18:46 +04:00
|
|
|
assert(openfile != NULL);
|
|
|
|
|
2015-12-18 13:41:09 +03:00
|
|
|
/* 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. */
|
|
|
|
for (; tmpcolor != NULL; tmpcolor = tmpcolor->next) {
|
|
|
|
foreground = tmpcolor->fg;
|
|
|
|
background = tmpcolor->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
|
|
|
|
2015-12-18 13:45:35 +03:00
|
|
|
init_pair(tmpcolor->pairnum, foreground, background);
|
2001-12-12 04:45:01 +03:00
|
|
|
#ifdef DEBUG
|
2015-12-18 13:41:09 +03:00
|
|
|
fprintf(stderr, "init_pair(): fg = %hd, bg = %hd\n", foreground, background);
|
2001-12-12 04:45:01 +03:00
|
|
|
#endif
|
2015-12-18 13:45:35 +03:00
|
|
|
}
|
2001-05-05 19:01:42 +04:00
|
|
|
}
|
|
|
|
|
2014-04-04 13:01:21 +04:00
|
|
|
/* Clean up a regex we previously compiled. */
|
2011-02-23 06:09:23 +03:00
|
|
|
void nfreeregex(regex_t **r)
|
2011-02-13 07:23:10 +03:00
|
|
|
{
|
|
|
|
assert(r != NULL);
|
|
|
|
|
2011-02-23 06:09:23 +03:00
|
|
|
regfree(*r);
|
|
|
|
free(*r);
|
|
|
|
*r = NULL;
|
2011-02-13 07:23:10 +03:00
|
|
|
}
|
|
|
|
|
2003-01-13 04:35:15 +03:00
|
|
|
/* Update the color information based on the current filename. */
|
2005-07-14 00:18:46 +04:00
|
|
|
void color_update(void)
|
2002-05-04 07:47:33 +04:00
|
|
|
{
|
2009-01-25 10:25:17 +03:00
|
|
|
syntaxtype *tmpsyntax;
|
|
|
|
syntaxtype *defsyntax = NULL;
|
2005-08-01 08:23:29 +04:00
|
|
|
colortype *tmpcolor, *defcolor = NULL;
|
2014-05-12 18:31:54 +04:00
|
|
|
regexlisttype *e;
|
2011-02-13 07:23:10 +03:00
|
|
|
|
2005-07-14 00:18:46 +04:00
|
|
|
assert(openfile != NULL);
|
2002-05-04 07:47:33 +04:00
|
|
|
|
2009-01-25 10:25:17 +03:00
|
|
|
openfile->syntax = NULL;
|
2005-07-14 00:18:46 +04:00
|
|
|
openfile->colorstrings = NULL;
|
2005-07-30 01:42:08 +04: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;
|
|
|
|
|
2005-07-31 01:24:56 +04:00
|
|
|
/* If we specified a syntax override string, use it. */
|
|
|
|
if (syntaxstr != NULL) {
|
2005-08-01 08:59:34 +04:00
|
|
|
/* If the syntax override is "none", it's the same as not having
|
|
|
|
* a syntax at all, so get out. */
|
|
|
|
if (strcmp(syntaxstr, "none") == 0)
|
|
|
|
return;
|
|
|
|
|
2005-07-31 01:24:56 +04:00
|
|
|
for (tmpsyntax = syntaxes; tmpsyntax != NULL;
|
|
|
|
tmpsyntax = tmpsyntax->next) {
|
2009-01-25 10:25:17 +03:00
|
|
|
if (strcmp(tmpsyntax->desc, syntaxstr) == 0) {
|
|
|
|
openfile->syntax = tmpsyntax;
|
2005-07-14 00:18:46 +04:00
|
|
|
openfile->colorstrings = tmpsyntax->color;
|
2009-01-25 10:25:17 +03:00
|
|
|
}
|
2002-05-13 00:54:16 +04:00
|
|
|
|
2005-07-14 00:18:46 +04:00
|
|
|
if (openfile->colorstrings != NULL)
|
2002-09-27 18:21:59 +04:00
|
|
|
break;
|
2002-05-04 07:47:33 +04:00
|
|
|
}
|
2015-11-24 14:42:19 +03:00
|
|
|
|
|
|
|
if (openfile->colorstrings == NULL)
|
|
|
|
statusbar(_("Unknown syntax name: %s"), syntaxstr);
|
2002-05-04 07:47:33 +04:00
|
|
|
}
|
2002-05-04 08:23:30 +04:00
|
|
|
|
2005-07-31 01:24:56 +04:00
|
|
|
/* If we didn't specify a syntax override string, or if we did and
|
|
|
|
* there was no syntax by that name, get the syntax based on the
|
2014-05-15 16:55:11 +04:00
|
|
|
* file extension, then try the headerline, and then try magic. */
|
2005-07-31 01:24:56 +04:00
|
|
|
if (openfile->colorstrings == NULL) {
|
2015-04-28 22:18:38 +03:00
|
|
|
char *currentdir = getcwd(NULL, PATH_MAX + 1);
|
|
|
|
char *joinednames = charalloc(PATH_MAX + 1);
|
|
|
|
char *fullname = NULL;
|
|
|
|
|
|
|
|
if (currentdir != NULL) {
|
|
|
|
/* Concatenate the current working directory with the
|
|
|
|
* specified filename, and canonicalize the result. */
|
|
|
|
sprintf(joinednames, "%s/%s", currentdir, openfile->filename);
|
|
|
|
fullname = realpath(joinednames, NULL);
|
|
|
|
free(currentdir);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fullname == NULL)
|
|
|
|
fullname = mallocstrcpy(fullname, openfile->filename);
|
|
|
|
|
2004-05-27 22:39:16 +04:00
|
|
|
for (tmpsyntax = syntaxes; tmpsyntax != NULL;
|
2005-03-10 23:55:11 +03:00
|
|
|
tmpsyntax = tmpsyntax->next) {
|
2005-07-31 01:24:56 +04:00
|
|
|
|
2005-08-01 08:23:29 +04:00
|
|
|
/* If this is the default syntax, it has no associated
|
2006-07-30 01:40:32 +04:00
|
|
|
* extensions, which we've checked for elsewhere. Skip over
|
|
|
|
* it here, but keep track of its color regexes. */
|
2005-08-01 08:34:27 +04:00
|
|
|
if (strcmp(tmpsyntax->desc, "default") == 0) {
|
2009-01-25 10:25:17 +03:00
|
|
|
defsyntax = tmpsyntax;
|
2006-05-28 22:51:48 +04:00
|
|
|
defcolor = tmpsyntax->color;
|
2005-08-01 08:23:29 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2005-07-31 01:24:56 +04:00
|
|
|
for (e = tmpsyntax->extensions; e != NULL; e = e->next) {
|
|
|
|
bool not_compiled = (e->ext == NULL);
|
|
|
|
|
|
|
|
/* e->ext_regex has already been checked for validity
|
|
|
|
* elsewhere. Compile its specified regex if we haven't
|
|
|
|
* already. */
|
|
|
|
if (not_compiled) {
|
|
|
|
e->ext = (regex_t *)nmalloc(sizeof(regex_t));
|
2008-08-30 09:16:20 +04:00
|
|
|
regcomp(e->ext, fixbounds(e->ext_regex), REG_EXTENDED);
|
2005-07-31 01:24:56 +04:00
|
|
|
}
|
|
|
|
|
2014-04-08 17:58:04 +04:00
|
|
|
/* Set colorstrings if we match the extension regex. */
|
2015-04-28 22:18:38 +03:00
|
|
|
if (regexec(e->ext, fullname, 0, NULL, 0) == 0) {
|
2009-01-25 10:25:17 +03:00
|
|
|
openfile->syntax = tmpsyntax;
|
2005-07-31 01:24:56 +04:00
|
|
|
openfile->colorstrings = tmpsyntax->color;
|
|
|
|
break;
|
2011-02-13 07:23:10 +03:00
|
|
|
}
|
2005-07-31 01:24:56 +04:00
|
|
|
|
|
|
|
/* Decompile e->ext_regex's specified regex if we aren't
|
|
|
|
* going to use it. */
|
2011-02-13 07:23:10 +03:00
|
|
|
if (not_compiled)
|
2011-02-23 06:09:23 +03:00
|
|
|
nfreeregex(&e->ext);
|
2011-02-13 07:23:10 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-28 22:18:38 +03:00
|
|
|
free(joinednames);
|
|
|
|
free(fullname);
|
|
|
|
|
2014-05-14 14:09:42 +04:00
|
|
|
/* Check the headerline if the extension didn't match anything. */
|
2011-02-13 07:23:10 +03:00
|
|
|
if (openfile->colorstrings == NULL) {
|
|
|
|
#ifdef DEBUG
|
2014-05-14 14:09:42 +04:00
|
|
|
fprintf(stderr, "No result from file extension, trying headerline...\n");
|
2014-03-17 18:15:57 +04:00
|
|
|
#endif
|
2011-02-13 07:23:10 +03:00
|
|
|
for (tmpsyntax = syntaxes; tmpsyntax != NULL;
|
|
|
|
tmpsyntax = tmpsyntax->next) {
|
2014-05-14 14:09:42 +04:00
|
|
|
|
|
|
|
for (e = tmpsyntax->headers; e != NULL; e = e->next) {
|
2011-02-13 07:23:10 +03:00
|
|
|
bool not_compiled = (e->ext == NULL);
|
2014-05-14 14:09:42 +04:00
|
|
|
|
2011-02-13 07:23:10 +03:00
|
|
|
if (not_compiled) {
|
|
|
|
e->ext = (regex_t *)nmalloc(sizeof(regex_t));
|
|
|
|
regcomp(e->ext, fixbounds(e->ext_regex), REG_EXTENDED);
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
2014-05-14 14:09:42 +04:00
|
|
|
fprintf(stderr, "Comparing header regex \"%s\" to fileage \"%s\"...\n",
|
|
|
|
e->ext_regex, openfile->fileage->data);
|
2014-03-17 18:15:57 +04:00
|
|
|
#endif
|
2014-05-14 14:09:42 +04:00
|
|
|
/* Set colorstrings if we match the header-line regex. */
|
|
|
|
if (regexec(e->ext, openfile->fileage->data, 0, NULL, 0) == 0) {
|
2011-02-13 07:23:10 +03:00
|
|
|
openfile->syntax = tmpsyntax;
|
|
|
|
openfile->colorstrings = tmpsyntax->color;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (not_compiled)
|
2011-02-23 06:09:23 +03:00
|
|
|
nfreeregex(&e->ext);
|
2005-07-31 01:24:56 +04:00
|
|
|
}
|
|
|
|
}
|
2005-07-14 00:18:46 +04:00
|
|
|
}
|
2008-09-22 03:02:30 +04:00
|
|
|
|
2014-05-14 14:09:42 +04:00
|
|
|
#ifdef HAVE_LIBMAGIC
|
|
|
|
/* Check magic if we don't have an answer yet. */
|
2008-09-22 03:02:30 +04:00
|
|
|
if (openfile->colorstrings == NULL) {
|
2014-06-30 21:49:53 +04:00
|
|
|
struct stat fileinfo;
|
|
|
|
magic_t cookie = NULL;
|
|
|
|
const char *magicstring = NULL;
|
2008-09-22 03:02:30 +04:00
|
|
|
#ifdef DEBUG
|
2014-05-14 14:09:42 +04:00
|
|
|
fprintf(stderr, "No result from headerline either, trying libmagic...\n");
|
2008-09-22 03:02:30 +04:00
|
|
|
#endif
|
2014-05-14 14:29:55 +04:00
|
|
|
if (stat(openfile->filename, &fileinfo) == 0) {
|
|
|
|
/* Open the magic database and get a diagnosis of the file. */
|
|
|
|
cookie = magic_open(MAGIC_SYMLINK |
|
|
|
|
#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);
|
2014-05-14 14:29:55 +04:00
|
|
|
if (cookie == NULL || magic_load(cookie, NULL) < 0)
|
|
|
|
statusbar(_("magic_load() failed: %s"), strerror(errno));
|
|
|
|
else {
|
|
|
|
magicstring = magic_file(cookie, openfile->filename);
|
|
|
|
if (magicstring == NULL) {
|
|
|
|
statusbar(_("magic_file(%s) failed: %s"),
|
|
|
|
openfile->filename, magic_error(cookie));
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
fprintf(stderr, "Returned magic string is: %s\n", magicstring);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now try and find a syntax that matches the magicstring. */
|
2008-09-22 03:02:30 +04:00
|
|
|
for (tmpsyntax = syntaxes; tmpsyntax != NULL;
|
|
|
|
tmpsyntax = tmpsyntax->next) {
|
|
|
|
|
2014-05-14 14:09:42 +04:00
|
|
|
for (e = tmpsyntax->magics; e != NULL; e = e->next) {
|
2008-09-22 03:02:30 +04:00
|
|
|
bool not_compiled = (e->ext == NULL);
|
|
|
|
|
|
|
|
if (not_compiled) {
|
|
|
|
e->ext = (regex_t *)nmalloc(sizeof(regex_t));
|
|
|
|
regcomp(e->ext, fixbounds(e->ext_regex), REG_EXTENDED);
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
2014-05-14 14:09:42 +04:00
|
|
|
fprintf(stderr, "Matching regex \"%s\" against \"%s\"\n", e->ext_regex, magicstring);
|
2008-09-22 03:02:30 +04:00
|
|
|
#endif
|
2014-05-14 14:09:42 +04:00
|
|
|
/* Set colorstrings if we match the magic-string regex. */
|
|
|
|
if (magicstring && regexec(e->ext, magicstring, 0, NULL, 0) == 0) {
|
2009-01-25 10:25:17 +03:00
|
|
|
openfile->syntax = tmpsyntax;
|
2008-09-22 03:02:30 +04:00
|
|
|
openfile->colorstrings = tmpsyntax->color;
|
|
|
|
break;
|
2014-04-08 17:58:04 +04:00
|
|
|
}
|
2008-09-22 03:02:30 +04:00
|
|
|
|
2011-02-13 07:23:10 +03:00
|
|
|
if (not_compiled)
|
2011-02-23 06:09:23 +03:00
|
|
|
nfreeregex(&e->ext);
|
2008-09-22 03:02:30 +04:00
|
|
|
}
|
2014-05-15 16:55:11 +04:00
|
|
|
if (openfile->syntax != NULL)
|
2014-05-14 15:51:26 +04:00
|
|
|
break;
|
2008-09-22 03:02:30 +04:00
|
|
|
}
|
2014-05-14 14:29:55 +04:00
|
|
|
if (stat(openfile->filename, &fileinfo) == 0)
|
|
|
|
magic_close(cookie);
|
2008-09-22 03:02:30 +04:00
|
|
|
}
|
2014-05-14 14:09:42 +04:00
|
|
|
#endif /* HAVE_LIBMAGIC */
|
2005-07-14 00:18:46 +04:00
|
|
|
}
|
|
|
|
|
2014-04-04 13:01:21 +04:00
|
|
|
/* If we didn't find any syntax yet, and we do have a default one,
|
|
|
|
* use it. */
|
2009-01-25 10:25:17 +03:00
|
|
|
if (openfile->colorstrings == NULL && defcolor != NULL) {
|
|
|
|
openfile->syntax = defsyntax;
|
2005-08-01 08:23:29 +04:00
|
|
|
openfile->colorstrings = defcolor;
|
2009-01-25 10:25:17 +03:00
|
|
|
}
|
2005-08-01 08:23:29 +04:00
|
|
|
|
2005-07-14 00:18:46 +04:00
|
|
|
for (tmpcolor = openfile->colorstrings; tmpcolor != NULL;
|
|
|
|
tmpcolor = tmpcolor->next) {
|
2005-07-30 01:42:08 +04:00
|
|
|
/* tmpcolor->start_regex and tmpcolor->end_regex have already
|
|
|
|
* been checked for validity elsewhere. Compile their specified
|
|
|
|
* regexes if we haven't already. */
|
|
|
|
if (tmpcolor->start == NULL) {
|
2005-07-14 00:18:46 +04:00
|
|
|
tmpcolor->start = (regex_t *)nmalloc(sizeof(regex_t));
|
2008-08-30 09:16:20 +04:00
|
|
|
regcomp(tmpcolor->start, fixbounds(tmpcolor->start_regex),
|
2005-07-14 22:33:51 +04:00
|
|
|
REG_EXTENDED | (tmpcolor->icase ? REG_ICASE : 0));
|
2005-07-14 00:18:46 +04:00
|
|
|
}
|
2005-07-14 22:33:51 +04:00
|
|
|
|
2005-07-30 01:42:08 +04:00
|
|
|
if (tmpcolor->end_regex != NULL && tmpcolor->end == NULL) {
|
2005-07-14 00:18:46 +04:00
|
|
|
tmpcolor->end = (regex_t *)nmalloc(sizeof(regex_t));
|
2008-08-30 09:16:20 +04:00
|
|
|
regcomp(tmpcolor->end, fixbounds(tmpcolor->end_regex),
|
2005-07-14 22:33:51 +04:00
|
|
|
REG_EXTENDED | (tmpcolor->icase ? REG_ICASE : 0));
|
2002-05-04 08:23:30 +04:00
|
|
|
}
|
|
|
|
}
|
2002-05-04 07:47:33 +04:00
|
|
|
}
|
|
|
|
|
2015-12-04 23:54:34 +03:00
|
|
|
/* Reset the multiline coloring cache for one specific regex (given by
|
|
|
|
* index) for lines that need reevaluation. */
|
|
|
|
void reset_multis_for_id(filestruct *fileptr, int index)
|
2009-02-06 06:41:02 +03:00
|
|
|
{
|
2015-12-04 23:54:34 +03:00
|
|
|
filestruct *row;
|
|
|
|
|
|
|
|
/* Reset the cache of earlier lines, as far back as needed. */
|
|
|
|
for (row = fileptr->prev; row != NULL; row = row->prev) {
|
|
|
|
alloc_multidata_if_needed(row);
|
|
|
|
if (row->multidata[index] == CNONE)
|
2009-02-06 06:41:02 +03:00
|
|
|
break;
|
2015-12-04 23:54:34 +03:00
|
|
|
row->multidata[index] = -1;
|
2009-02-06 06:41:02 +03:00
|
|
|
}
|
2015-12-04 23:54:34 +03:00
|
|
|
for (; row != NULL; row = row->prev) {
|
|
|
|
alloc_multidata_if_needed(row);
|
|
|
|
if (row->multidata[index] != CNONE)
|
2009-02-08 21:00:44 +03:00
|
|
|
break;
|
2015-12-04 23:54:34 +03:00
|
|
|
row->multidata[index] = -1;
|
2009-02-08 21:00:44 +03:00
|
|
|
}
|
2009-02-06 06:41:02 +03:00
|
|
|
|
2015-12-04 23:54:34 +03:00
|
|
|
/* Reset the cache of the current line. */
|
|
|
|
fileptr->multidata[index] = -1;
|
|
|
|
|
|
|
|
/* Reset the cache of later lines, as far ahead as needed. */
|
|
|
|
for (row = fileptr->next; row != NULL; row = row->next) {
|
|
|
|
alloc_multidata_if_needed(row);
|
|
|
|
if (row->multidata[index] == CNONE)
|
2009-02-06 06:41:02 +03:00
|
|
|
break;
|
2015-12-04 23:54:34 +03:00
|
|
|
row->multidata[index] = -1;
|
2009-02-06 06:41:02 +03:00
|
|
|
}
|
2015-12-04 23:54:34 +03:00
|
|
|
for (; row != NULL; row = row->next) {
|
|
|
|
alloc_multidata_if_needed(row);
|
|
|
|
if (row->multidata[index] != CNONE)
|
2009-02-08 21:00:44 +03:00
|
|
|
break;
|
2015-12-04 23:54:34 +03:00
|
|
|
row->multidata[index] = -1;
|
2009-02-08 21:00:44 +03:00
|
|
|
}
|
2009-02-06 06:41:02 +03:00
|
|
|
|
2015-12-04 23:54:34 +03:00
|
|
|
edit_refresh_needed = TRUE;
|
2009-02-17 00:04:00 +03:00
|
|
|
}
|
2009-02-06 06:41:02 +03:00
|
|
|
|
2015-11-29 13:43:10 +03:00
|
|
|
/* Reset multi-line strings around the filestruct fileptr, trying to be
|
|
|
|
* smart about stopping. Bool force means: reset everything regardless,
|
|
|
|
* useful when we don't know how much screen state has changed. */
|
2009-02-17 00:04:00 +03:00
|
|
|
void reset_multis(filestruct *fileptr, bool force)
|
2009-02-06 06:41:02 +03:00
|
|
|
{
|
|
|
|
int nobegin, noend;
|
|
|
|
regmatch_t startmatch, endmatch;
|
|
|
|
const colortype *tmpcolor = openfile->colorstrings;
|
2009-01-25 10:25:17 +03:00
|
|
|
|
2009-01-30 11:34:27 +03:00
|
|
|
if (!openfile->syntax)
|
|
|
|
return;
|
|
|
|
|
2009-02-06 06:41:02 +03:00
|
|
|
for (; tmpcolor != NULL; tmpcolor = tmpcolor->next) {
|
2014-04-04 13:01:21 +04:00
|
|
|
/* If it's not a multi-line regex, amscray. */
|
2009-02-06 06:41:02 +03:00
|
|
|
if (tmpcolor->end == NULL)
|
|
|
|
continue;
|
|
|
|
|
2009-02-07 17:48:30 +03:00
|
|
|
alloc_multidata_if_needed(fileptr);
|
2009-02-17 00:04:00 +03:00
|
|
|
|
2015-11-29 13:43:10 +03:00
|
|
|
if (force == FALSE) {
|
|
|
|
/* Check whether the multidata still matches the current situation. */
|
|
|
|
nobegin = regexec(tmpcolor->start, fileptr->data, 1, &startmatch, 0);
|
|
|
|
noend = regexec(tmpcolor->end, fileptr->data, 1, &endmatch, 0);
|
|
|
|
if ((fileptr->multidata[tmpcolor->id] == CWHOLELINE ||
|
|
|
|
fileptr->multidata[tmpcolor->id] == CNONE) &&
|
|
|
|
nobegin && noend)
|
2009-02-17 02:06:09 +03:00
|
|
|
continue;
|
2015-11-29 13:43:10 +03:00
|
|
|
else if (fileptr->multidata[tmpcolor->id] == CSTARTENDHERE &&
|
2015-11-29 13:14:25 +03:00
|
|
|
!nobegin && !noend && startmatch.rm_so < endmatch.rm_so)
|
2015-11-29 13:43:10 +03:00
|
|
|
continue;
|
|
|
|
else if (fileptr->multidata[tmpcolor->id] == CBEGINBEFORE &&
|
|
|
|
nobegin && !noend)
|
|
|
|
continue;
|
|
|
|
else if (fileptr->multidata[tmpcolor->id] == CENDAFTER &&
|
2015-11-29 13:14:25 +03:00
|
|
|
!nobegin && noend)
|
2015-11-29 13:43:10 +03:00
|
|
|
continue;
|
|
|
|
}
|
2009-02-06 06:41:02 +03:00
|
|
|
|
2015-11-29 13:43:10 +03:00
|
|
|
/* If we got here, things have changed. */
|
2009-02-17 00:04:00 +03:00
|
|
|
reset_multis_for_id(fileptr, tmpcolor->id);
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Poll the keyboard every second to see if the user starts typing. */
|
|
|
|
bool key_was_pressed(void)
|
|
|
|
{
|
|
|
|
static time_t last_time = 0;
|
|
|
|
|
|
|
|
if (time(NULL) != last_time) {
|
|
|
|
last_time = time(NULL);
|
|
|
|
return (wgetch(edit) != ERR);
|
|
|
|
} else
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Precalculate the multi-line start and end regex info so we can
|
|
|
|
* speed up rendering (with any hope at all...). */
|
|
|
|
void precalc_multicolorinfo(void)
|
|
|
|
{
|
|
|
|
const colortype *tmpcolor = openfile->colorstrings;
|
|
|
|
regmatch_t startmatch, endmatch;
|
|
|
|
filestruct *fileptr, *endptr;
|
|
|
|
|
|
|
|
if (openfile->colorstrings == NULL || ISSET(NO_COLOR_SYNTAX))
|
|
|
|
return;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
fprintf(stderr, "Entering precalculation of multiline color info\n");
|
|
|
|
#endif
|
|
|
|
/* Let us get keypresses to see if the user is trying to start
|
|
|
|
* editing. Later we may want to throw up a statusbar message
|
|
|
|
* before starting this if it takes too long to do this routine.
|
|
|
|
* For now silently abort if they hit a key. */
|
|
|
|
nodelay(edit, TRUE);
|
|
|
|
|
|
|
|
for (; tmpcolor != NULL; tmpcolor = tmpcolor->next) {
|
|
|
|
/* If this is not a multi-line regex, skip it. */
|
|
|
|
if (tmpcolor->end == NULL)
|
|
|
|
continue;
|
|
|
|
#ifdef DEBUG
|
|
|
|
fprintf(stderr, "Starting work on color id %d\n", tmpcolor->id);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for (fileptr = openfile->fileage; fileptr != NULL; fileptr = fileptr->next) {
|
|
|
|
int startx = 0, nostart = 0;
|
|
|
|
|
|
|
|
if (key_was_pressed())
|
|
|
|
goto precalc_cleanup;
|
|
|
|
#ifdef DEBUG
|
|
|
|
fprintf(stderr, "working on lineno %ld... ", (long)fileptr->lineno);
|
|
|
|
#endif
|
|
|
|
alloc_multidata_if_needed(fileptr);
|
|
|
|
|
|
|
|
while ((nostart = regexec(tmpcolor->start, &fileptr->data[startx],
|
|
|
|
1, &startmatch, (startx == 0) ? 0 : REG_NOTBOL)) == 0) {
|
|
|
|
/* Look for an end, and start marking how many lines are
|
|
|
|
* encompassed, which should speed up rendering later. */
|
|
|
|
startx += startmatch.rm_eo;
|
|
|
|
#ifdef DEBUG
|
|
|
|
fprintf(stderr, "start found at pos %lu... ", (unsigned long)startx);
|
|
|
|
#endif
|
|
|
|
/* Look first on this line for an end. */
|
|
|
|
if (regexec(tmpcolor->end, &fileptr->data[startx], 1,
|
|
|
|
&endmatch, (startx == 0) ? 0 : REG_NOTBOL) == 0) {
|
|
|
|
startx += endmatch.rm_eo;
|
|
|
|
fileptr->multidata[tmpcolor->id] = CSTARTENDHERE;
|
|
|
|
#ifdef DEBUG
|
|
|
|
fprintf(stderr, "end found on this line\n");
|
|
|
|
#endif
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Nice, we didn't find the end regex on this line. Let's start looking for it. */
|
|
|
|
for (endptr = fileptr->next; endptr != NULL; endptr = endptr->next) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
fprintf(stderr, "\nadvancing to line %ld to find end... ", (long)endptr->lineno);
|
|
|
|
#endif
|
|
|
|
/* Check for interrupting keyboard input again. */
|
|
|
|
if (key_was_pressed())
|
|
|
|
goto precalc_cleanup;
|
|
|
|
|
|
|
|
if (regexec(tmpcolor->end, endptr->data, 1, &endmatch, 0) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (endptr == NULL) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
fprintf(stderr, "no end found, breaking out\n");
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
fprintf(stderr, "end found\n");
|
|
|
|
#endif
|
|
|
|
/* We found it, we found it, la la la la la. Mark all
|
|
|
|
* the lines in between and the end properly. */
|
|
|
|
fileptr->multidata[tmpcolor->id] = CENDAFTER;
|
|
|
|
#ifdef DEBUG
|
|
|
|
fprintf(stderr, "marking line %ld as CENDAFTER\n", (long)fileptr->lineno);
|
|
|
|
#endif
|
|
|
|
for (fileptr = fileptr->next; fileptr != endptr; fileptr = fileptr->next) {
|
|
|
|
alloc_multidata_if_needed(fileptr);
|
|
|
|
fileptr->multidata[tmpcolor->id] = CWHOLELINE;
|
|
|
|
#ifdef DEBUG
|
|
|
|
fprintf(stderr, "marking intermediary line %ld as CWHOLELINE\n", (long)fileptr->lineno);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
alloc_multidata_if_needed(endptr);
|
|
|
|
fileptr->multidata[tmpcolor->id] = CBEGINBEFORE;
|
|
|
|
#ifdef DEBUG
|
|
|
|
fprintf(stderr, "marking line %ld as CBEGINBEFORE\n", (long)fileptr->lineno);
|
|
|
|
#endif
|
|
|
|
/* Skip to the end point of the match. */
|
|
|
|
startx = endmatch.rm_eo;
|
|
|
|
#ifdef DEBUG
|
|
|
|
fprintf(stderr, "jumping to line %ld pos %lu to continue\n", (long)fileptr->lineno, (unsigned long)startx);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nostart && startx == 0) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
fprintf(stderr, "no match\n");
|
|
|
|
#endif
|
|
|
|
fileptr->multidata[tmpcolor->id] = CNONE;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
precalc_cleanup:
|
|
|
|
nodelay(edit, FALSE);
|
|
|
|
}
|
|
|
|
|
2014-04-04 15:59:03 +04:00
|
|
|
#endif /* !DISABLE_COLOR */
|