mirror of
git://git.sv.gnu.org/nano.git
synced 2024-11-22 12:51:23 +03:00
add DB's overhaul of the rcfile parsing code and related miscellaneous
bits git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@2345 35c25a1d-7b9e-4130-9fde-d3aeb78583b8
This commit is contained in:
parent
40f11ae622
commit
202d3c2f97
@ -162,6 +162,15 @@ CVS code -
|
||||
routine to get the current user's home directory into the new
|
||||
function get_homedir(), and use it where necessary. Also add
|
||||
a few miscellaneous tweaks.
|
||||
- Overhaul the rcfile parsing code to make it simpler and more
|
||||
accurate, remove now-redundant checks from the color code,
|
||||
change the COLOR_SYNTAX toggle to the NO_COLOR_SYMTAX toggle,
|
||||
and improve various debugging messsages. Changes to
|
||||
set_colorpairs(), do_colorinit(), parse_next_word(),
|
||||
parse_argument(), colortoint(), parse_next_regex(),
|
||||
parse_syntax(), parse_colors(), parse_rcfile(), do_rcfile(),
|
||||
etc. (David Benbennick) DLR: Rename colortoint() to
|
||||
color_to_int(), and add a few miscellaneous tweaks.
|
||||
- cut.c:
|
||||
do_cut_text()
|
||||
- If keep_cutbuffer is FALSE, only blow away the text in the
|
||||
|
33
src/color.c
33
src/color.c
@ -2,7 +2,7 @@
|
||||
/**************************************************************************
|
||||
* color.c *
|
||||
* *
|
||||
* Copyright (C) 1999-2004 Chris Allegretta *
|
||||
* Copyright (C) 1999-2005 Chris Allegretta *
|
||||
* 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 *
|
||||
* the Free Software Foundation; either version 2, or (at your option) *
|
||||
@ -46,14 +46,14 @@ void set_colorpairs(void)
|
||||
for (; this_color != NULL; this_color = this_color->next) {
|
||||
const colortype *beforenow = this_syntax->color;
|
||||
|
||||
for (; beforenow != NULL && beforenow != this_color &&
|
||||
(beforenow->fg != this_color->fg ||
|
||||
beforenow->bg != this_color->bg ||
|
||||
beforenow->bright != this_color->bright);
|
||||
beforenow = beforenow->next)
|
||||
for (; beforenow != this_color &&
|
||||
(beforenow->fg != this_color->fg ||
|
||||
beforenow->bg != this_color->bg ||
|
||||
beforenow->bright != this_color->bright);
|
||||
beforenow = beforenow->next)
|
||||
;
|
||||
|
||||
if (beforenow != NULL && beforenow != this_color)
|
||||
if (beforenow != this_color)
|
||||
this_color->pairnum = beforenow->pairnum;
|
||||
else {
|
||||
this_color->pairnum = color_pair;
|
||||
@ -68,14 +68,14 @@ void do_colorinit(void)
|
||||
if (has_colors()) {
|
||||
const colortype *tmpcolor = NULL;
|
||||
#ifdef HAVE_USE_DEFAULT_COLORS
|
||||
int defok;
|
||||
bool defok;
|
||||
#endif
|
||||
|
||||
start_color();
|
||||
/* Add in colors, if available */
|
||||
|
||||
/* Add in colors, if available. */
|
||||
#ifdef HAVE_USE_DEFAULT_COLORS
|
||||
defok = use_default_colors() != ERR;
|
||||
defok = (use_default_colors() != ERR);
|
||||
#endif
|
||||
|
||||
for (tmpcolor = colorstrings; tmpcolor != NULL;
|
||||
@ -91,8 +91,8 @@ void do_colorinit(void)
|
||||
init_pair(tmpcolor->pairnum, tmpcolor->fg, background);
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Running %s with fg = %d and bg = %d\n",
|
||||
"init_pair()", tmpcolor->fg, tmpcolor->bg);
|
||||
fprintf(stderr, "init_pair(): fg = %d, bg = %d\n",
|
||||
tmpcolor->fg, tmpcolor->bg);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -104,11 +104,12 @@ void update_color(void)
|
||||
const syntaxtype *tmpsyntax;
|
||||
|
||||
colorstrings = NULL;
|
||||
for (tmpsyntax = syntaxes; tmpsyntax != NULL; tmpsyntax = tmpsyntax->next) {
|
||||
for (tmpsyntax = syntaxes; tmpsyntax != NULL;
|
||||
tmpsyntax = tmpsyntax->next) {
|
||||
const exttype *e;
|
||||
|
||||
for (e = tmpsyntax->extensions; e != NULL; e = e->next) {
|
||||
/* Set colorstrings if we matched the extension regex */
|
||||
/* Set colorstrings if we matched the extension regex. */
|
||||
if (regexec(&e->val, filename, 0, NULL, 0) == 0)
|
||||
colorstrings = tmpsyntax->color;
|
||||
|
||||
@ -117,10 +118,10 @@ void update_color(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* if we haven't found a match, use the override string */
|
||||
/* If we haven't found a match, use the override string. */
|
||||
if (colorstrings == NULL && syntaxstr != NULL) {
|
||||
for (tmpsyntax = syntaxes; tmpsyntax != NULL;
|
||||
tmpsyntax = tmpsyntax->next) {
|
||||
tmpsyntax = tmpsyntax->next) {
|
||||
if (strcasecmp(tmpsyntax->desc, syntaxstr) == 0)
|
||||
colorstrings = tmpsyntax->color;
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ void new_file(void)
|
||||
|
||||
#ifdef ENABLE_COLOR
|
||||
update_color();
|
||||
if (ISSET(COLOR_SYNTAX))
|
||||
if (!ISSET(NO_COLOR_SYNTAX))
|
||||
edit_refresh();
|
||||
#endif
|
||||
}
|
||||
@ -675,7 +675,7 @@ void do_insertfile(
|
||||
|
||||
break;
|
||||
}
|
||||
} /* while (TRUE) */
|
||||
}
|
||||
|
||||
free(ans);
|
||||
}
|
||||
@ -1640,7 +1640,7 @@ int write_file(const char *name, bool tmp, int append, bool
|
||||
filename = mallocstrcpy(filename, realname);
|
||||
#ifdef ENABLE_COLOR
|
||||
update_color();
|
||||
if (ISSET(COLOR_SYNTAX))
|
||||
if (!ISSET(NO_COLOR_SYNTAX))
|
||||
edit_refresh();
|
||||
#endif
|
||||
}
|
||||
|
@ -1106,7 +1106,7 @@ void toggle_init(void)
|
||||
SMART_HOME);
|
||||
#ifdef ENABLE_COLOR
|
||||
toggle_init_one(TOGGLE_SYNTAX_KEY, N_("Color syntax highlighting"),
|
||||
COLOR_SYNTAX);
|
||||
NO_COLOR_SYNTAX);
|
||||
#endif
|
||||
#ifdef ENABLE_NANORC
|
||||
toggle_init_one(TOGGLE_WHITESPACE_KEY, N_("Whitespace display"),
|
||||
|
@ -1299,7 +1299,7 @@ void do_delete(void)
|
||||
#ifdef ENABLE_COLOR
|
||||
/* If color syntaxes are turned on, we need to call
|
||||
* edit_refresh(). */
|
||||
if (ISSET(COLOR_SYNTAX))
|
||||
if (!ISSET(NO_COLOR_SYNTAX))
|
||||
do_refresh = TRUE;
|
||||
#endif
|
||||
|
||||
@ -3833,7 +3833,7 @@ void do_output(char *output, size_t output_len)
|
||||
#ifdef ENABLE_COLOR
|
||||
/* If color syntaxes are turned on, we need to call
|
||||
* edit_refresh(). */
|
||||
if (ISSET(COLOR_SYNTAX))
|
||||
if (!ISSET(NO_COLOR_SYNTAX))
|
||||
do_refresh = TRUE;
|
||||
#endif
|
||||
}
|
||||
|
@ -291,7 +291,7 @@ typedef struct historyheadtype {
|
||||
#define NO_CONVERT (1<<19)
|
||||
#define BACKUP_FILE (1<<20)
|
||||
#define NO_RCFILE (1<<21)
|
||||
#define COLOR_SYNTAX (1<<22)
|
||||
#define NO_COLOR_SYNTAX (1<<22)
|
||||
#define PRESERVE (1<<23)
|
||||
#define HISTORY_CHANGED (1<<24)
|
||||
#define HISTORYLOG (1<<25)
|
||||
|
@ -462,9 +462,9 @@ void rcfile_error(const char *msg, ...);
|
||||
char *parse_next_word(char *ptr);
|
||||
char *parse_argument(char *ptr);
|
||||
#ifdef ENABLE_COLOR
|
||||
int colortoint(const char *colorname, int *bright);
|
||||
int color_to_int(const char *colorname, bool *bright);
|
||||
char *parse_next_regex(char *ptr);
|
||||
int nregcomp(regex_t *preg, const char *regex, int eflags);
|
||||
bool nregcomp(regex_t *preg, const char *regex, int eflags);
|
||||
void parse_syntax(char *ptr);
|
||||
void parse_colors(char *ptr);
|
||||
#endif /* ENABLE_COLOR */
|
||||
|
498
src/rcfile.c
498
src/rcfile.c
@ -29,7 +29,6 @@
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include "proto.h"
|
||||
@ -102,10 +101,16 @@ const static rcoption rcopts[] = {
|
||||
|
||||
static bool errors = FALSE;
|
||||
static int lineno = 0;
|
||||
static const char *nanorc;
|
||||
static char *nanorc = NULL;
|
||||
#ifdef ENABLE_COLOR
|
||||
static syntaxtype *endsyntax = NULL;
|
||||
/* The end of the list of syntaxes. */
|
||||
static colortype *endcolor = NULL;
|
||||
/* The end of the color list for the current syntax. */
|
||||
#endif
|
||||
|
||||
/* We have an error in some part of the rcfile; put it on stderr and
|
||||
make the user hit return to continue starting up nano. */
|
||||
/* We have an error in some part of the rcfile. Put it on stderr and
|
||||
* make the user hit return to continue starting up nano. */
|
||||
void rcfile_error(const char *msg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
@ -123,17 +128,18 @@ void rcfile_error(const char *msg, ...)
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
/* Parse the next word from the string. Returns NULL if we hit EOL. */
|
||||
/* Parse the next word from the string. Return points to '\0' if we hit
|
||||
* the end of the line. */
|
||||
char *parse_next_word(char *ptr)
|
||||
{
|
||||
while (!is_blank_char(*ptr) && *ptr != '\n' && *ptr != '\0')
|
||||
while (!is_blank_char(*ptr) && *ptr != '\0')
|
||||
ptr++;
|
||||
|
||||
if (*ptr == '\0')
|
||||
return NULL;
|
||||
return ptr;
|
||||
|
||||
/* Null terminate and advance ptr */
|
||||
*ptr++ = 0;
|
||||
/* Null-terminate and advance ptr. */
|
||||
*ptr++ = '\0';
|
||||
|
||||
while (is_blank_char(*ptr))
|
||||
ptr++;
|
||||
@ -141,13 +147,13 @@ char *parse_next_word(char *ptr)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* The keywords operatingdir, backupdir, fill, tabsize, speller,
|
||||
* punct, brackets, quotestr, and whitespace take an argument when set.
|
||||
* Among these, operatingdir, backupdir, speller, punct, brackets,
|
||||
* quotestr, and whitespace have to allow tabs and spaces in the
|
||||
* argument. Thus, if the next word starts with a ", we say it ends
|
||||
* with the last " of the line. Otherwise, the word is interpreted as
|
||||
* usual. That is so the arguments can contain "s too. */
|
||||
/* The keywords operatingdir, backupdir, fill, tabsize, speller, punct,
|
||||
* brackets, quotestr, and whitespace take an argument when set. Among
|
||||
* these, operatingdir, backupdir, speller, punct, brackets, quotestr,
|
||||
* and whitespace have to allow tabs and spaces in the argument. Thus,
|
||||
* if the next word starts with a ", we say it ends with the last " of
|
||||
* the line. Otherwise, the word is interpreted as usual. That is so
|
||||
* the arguments can contain "s too. */
|
||||
char *parse_argument(char *ptr)
|
||||
{
|
||||
const char *ptr_bak = ptr;
|
||||
@ -162,7 +168,7 @@ char *parse_argument(char *ptr)
|
||||
ptr++;
|
||||
if (*ptr == '"')
|
||||
last_quote = ptr;
|
||||
} while (*ptr != '\n' && *ptr != '\0');
|
||||
} while (*ptr != '\0');
|
||||
|
||||
if (last_quote == NULL) {
|
||||
if (*ptr == '\0')
|
||||
@ -181,16 +187,19 @@ char *parse_argument(char *ptr)
|
||||
}
|
||||
|
||||
#ifdef ENABLE_COLOR
|
||||
|
||||
int colortoint(const char *colorname, int *bright)
|
||||
int color_to_int(const char *colorname, bool *bright)
|
||||
{
|
||||
int mcolor = 0;
|
||||
int mcolor = -1;
|
||||
|
||||
if (colorname == NULL)
|
||||
if (colorname == NULL) {
|
||||
rcfile_error(N_("Missing color name"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(bright != NULL);
|
||||
|
||||
if (strncasecmp(colorname, "bright", 6) == 0) {
|
||||
*bright = 1;
|
||||
*bright = TRUE;
|
||||
colorname += 6;
|
||||
}
|
||||
|
||||
@ -210,25 +219,32 @@ int colortoint(const char *colorname, int *bright)
|
||||
mcolor = COLOR_MAGENTA;
|
||||
else if (strcasecmp(colorname, "black") == 0)
|
||||
mcolor = COLOR_BLACK;
|
||||
else {
|
||||
else
|
||||
rcfile_error(N_("Color %s not understood.\n"
|
||||
"Valid colors are \"green\", \"red\", \"blue\", \n"
|
||||
"\"white\", \"yellow\", \"cyan\", \"magenta\" and \n"
|
||||
"\"black\", with the optional prefix \"bright\" \n"
|
||||
"Valid colors are \"green\", \"red\", \"blue\",\n"
|
||||
"\"white\", \"yellow\", \"cyan\", \"magenta\" and\n"
|
||||
"\"black\", with the optional prefix \"bright\"\n"
|
||||
"for foreground colors."), colorname);
|
||||
mcolor = -1;
|
||||
}
|
||||
|
||||
return mcolor;
|
||||
}
|
||||
|
||||
char *parse_next_regex(char *ptr)
|
||||
{
|
||||
while ((*ptr != '"' || (*(ptr + 1) != ' ' && *(ptr + 1) != '\n'))
|
||||
&& *ptr != '\n' && *ptr != '\0')
|
||||
assert(ptr != NULL);
|
||||
|
||||
/* Continue until the end of the line, or a " followed by a space, a
|
||||
* blank character, or \0. */
|
||||
while ((*ptr != '"' || (!is_blank_char(*(ptr + 1)) &&
|
||||
*(ptr + 1) != '\0')) && *ptr != '\0')
|
||||
ptr++;
|
||||
|
||||
if (*ptr == '\0')
|
||||
assert(*ptr == '"' || *ptr == '\0');
|
||||
|
||||
if (*ptr == '\0') {
|
||||
rcfile_error(N_("Regex strings must begin and end with a \" character"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Null terminate and advance ptr. */
|
||||
*ptr++ = '\0';
|
||||
@ -239,9 +255,9 @@ char *parse_next_regex(char *ptr)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* Compile the regular expression regex to preg. Returns FALSE on
|
||||
/* Compile the regular expression regex to preg. Return FALSE on
|
||||
* success, or TRUE if the expression is invalid. */
|
||||
int nregcomp(regex_t *preg, const char *regex, int eflags)
|
||||
bool nregcomp(regex_t *preg, const char *regex, int eflags)
|
||||
{
|
||||
int rc = regcomp(preg, regex, REG_EXTENDED | eflags);
|
||||
|
||||
@ -259,75 +275,73 @@ int nregcomp(regex_t *preg, const char *regex, int eflags)
|
||||
|
||||
void parse_syntax(char *ptr)
|
||||
{
|
||||
syntaxtype *tmpsyntax = NULL;
|
||||
const char *fileregptr = NULL, *nameptr = NULL;
|
||||
exttype *endext = NULL;
|
||||
/* The end of the extensions list for this syntax. */
|
||||
|
||||
while (*ptr == ' ')
|
||||
ptr++;
|
||||
assert(ptr != NULL);
|
||||
|
||||
if (*ptr == '\n' || *ptr == '\0')
|
||||
if (*ptr == '\0') {
|
||||
rcfile_error(N_("Missing syntax name"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (*ptr != '"') {
|
||||
rcfile_error(N_("Regex strings must begin and end with a \" character"));
|
||||
return;
|
||||
}
|
||||
|
||||
ptr++;
|
||||
|
||||
nameptr = ptr;
|
||||
ptr = parse_next_regex(ptr);
|
||||
|
||||
if (ptr == NULL) {
|
||||
rcfile_error(N_("Missing syntax name"));
|
||||
if (ptr == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
if (syntaxes == NULL) {
|
||||
syntaxes = (syntaxtype *)nmalloc(sizeof(syntaxtype));
|
||||
tmpsyntax = syntaxes;
|
||||
SET(COLOR_SYNTAX);
|
||||
endsyntax = syntaxes;
|
||||
} else {
|
||||
for (tmpsyntax = syntaxes; tmpsyntax->next != NULL;
|
||||
tmpsyntax = tmpsyntax->next)
|
||||
;
|
||||
tmpsyntax->next = (syntaxtype *)nmalloc(sizeof(syntaxtype));
|
||||
tmpsyntax = tmpsyntax->next;
|
||||
endsyntax->next = (syntaxtype *)nmalloc(sizeof(syntaxtype));
|
||||
endsyntax = endsyntax->next;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Adding new syntax after 1st\n");
|
||||
fprintf(stderr, "Adding new syntax after first one\n");
|
||||
#endif
|
||||
}
|
||||
tmpsyntax->desc = mallocstrcpy(NULL, nameptr);
|
||||
tmpsyntax->color = NULL;
|
||||
tmpsyntax->extensions = NULL;
|
||||
tmpsyntax->next = NULL;
|
||||
endsyntax->desc = mallocstrcpy(NULL, nameptr);
|
||||
endsyntax->color = NULL;
|
||||
endcolor = NULL;
|
||||
endsyntax->extensions = NULL;
|
||||
endsyntax->next = NULL;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Starting a new syntax type\n");
|
||||
fprintf(stderr, "string val=%s\n", nameptr);
|
||||
fprintf(stderr, "Starting a new syntax type: \"%s\"\n", nameptr);
|
||||
#endif
|
||||
|
||||
/* Now load in the extensions to their part of the struct */
|
||||
while (*ptr != '\n' && *ptr != '\0') {
|
||||
/* Now load the extensions into their part of the struct. */
|
||||
while (*ptr != '\0') {
|
||||
exttype *newext;
|
||||
/* The new extension structure. */
|
||||
|
||||
while (*ptr != '"' && *ptr != '\n' && *ptr != '\0')
|
||||
while (*ptr != '"' && *ptr != '\0')
|
||||
ptr++;
|
||||
|
||||
if (*ptr == '\n' || *ptr == '\0')
|
||||
if (*ptr == '\0')
|
||||
return;
|
||||
|
||||
ptr++;
|
||||
|
||||
fileregptr = ptr;
|
||||
ptr = parse_next_regex(ptr);
|
||||
if (ptr == NULL)
|
||||
break;
|
||||
|
||||
newext = (exttype *)nmalloc(sizeof(exttype));
|
||||
if (nregcomp(&newext->val, fileregptr, REG_NOSUB) != 0)
|
||||
if (nregcomp(&newext->val, fileregptr, REG_NOSUB))
|
||||
free(newext);
|
||||
else {
|
||||
if (endext == NULL)
|
||||
tmpsyntax->extensions = newext;
|
||||
endsyntax->extensions = newext;
|
||||
else
|
||||
endext->next = newext;
|
||||
endext = newext;
|
||||
@ -336,24 +350,24 @@ void parse_syntax(char *ptr)
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse the color stuff into the colorstrings array */
|
||||
/* Parse the color stuff into the colorstrings array. */
|
||||
void parse_colors(char *ptr)
|
||||
{
|
||||
int fg, bg, bright = 0;
|
||||
int expectend = 0; /* Do we expect an end= line? */
|
||||
int fg, bg;
|
||||
bool bright = FALSE;
|
||||
char *fgstr;
|
||||
colortype *tmpcolor = NULL;
|
||||
syntaxtype *tmpsyntax = NULL;
|
||||
|
||||
fgstr = ptr;
|
||||
ptr = parse_next_word(ptr);
|
||||
assert(ptr != NULL);
|
||||
|
||||
if (ptr == NULL) {
|
||||
if (*ptr == '\0') {
|
||||
rcfile_error(N_("Missing color name"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (strstr(fgstr, ",")) {
|
||||
fgstr = ptr;
|
||||
ptr = parse_next_word(ptr);
|
||||
|
||||
if (strchr(fgstr, ',') != NULL) {
|
||||
char *bgcolorname;
|
||||
strtok(fgstr, ",");
|
||||
bgcolorname = strtok(NULL, ",");
|
||||
@ -361,13 +375,14 @@ void parse_colors(char *ptr)
|
||||
rcfile_error(N_("Background color %s cannot be bright"), bgcolorname);
|
||||
return;
|
||||
}
|
||||
bg = colortoint(bgcolorname, &bright);
|
||||
|
||||
bg = color_to_int(bgcolorname, &bright);
|
||||
} else
|
||||
bg = -1;
|
||||
|
||||
fg = colortoint(fgstr, &bright);
|
||||
fg = color_to_int(fgstr, &bright);
|
||||
|
||||
/* Don't try and parse screwed up fg colors */
|
||||
/* Don't try to parse screwed-up foreground colors. */
|
||||
if (fg == -1)
|
||||
return;
|
||||
|
||||
@ -376,28 +391,20 @@ void parse_colors(char *ptr)
|
||||
return;
|
||||
}
|
||||
|
||||
for (tmpsyntax = syntaxes; tmpsyntax->next != NULL;
|
||||
tmpsyntax = tmpsyntax->next)
|
||||
;
|
||||
/* Now for the fun part. Start adding regexps to individual strings
|
||||
* in the colorstrings array, woo! */
|
||||
|
||||
/* Now the fun part, start adding regexps to individual strings
|
||||
in the colorstrings array, woo! */
|
||||
|
||||
while (*ptr != '\0') {
|
||||
while (ptr != NULL && *ptr != '\0') {
|
||||
colortype *newcolor;
|
||||
/* The new color structure. */
|
||||
int cancelled = 0;
|
||||
bool cancelled = FALSE;
|
||||
/* The start expression was bad. */
|
||||
|
||||
while (*ptr == ' ')
|
||||
ptr++;
|
||||
|
||||
if (*ptr == '\n' || *ptr == '\0')
|
||||
break;
|
||||
bool expectend = FALSE;
|
||||
/* Do we expect an end= line? */
|
||||
|
||||
if (strncasecmp(ptr, "start=", 6) == 0) {
|
||||
ptr += 6;
|
||||
expectend = 1;
|
||||
expectend = TRUE;
|
||||
}
|
||||
|
||||
if (*ptr != '"') {
|
||||
@ -405,14 +412,18 @@ void parse_colors(char *ptr)
|
||||
ptr = parse_next_regex(ptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
ptr++;
|
||||
|
||||
newcolor = (colortype *)nmalloc(sizeof(colortype));
|
||||
fgstr = ptr;
|
||||
ptr = parse_next_regex(ptr);
|
||||
if (nregcomp(&newcolor->start, fgstr, 0) != 0) {
|
||||
if (ptr == NULL)
|
||||
break;
|
||||
|
||||
if (nregcomp(&newcolor->start, fgstr, 0)) {
|
||||
free(newcolor);
|
||||
cancelled = 1;
|
||||
cancelled = TRUE;
|
||||
} else {
|
||||
newcolor->fg = fg;
|
||||
newcolor->bg = bg;
|
||||
@ -420,20 +431,18 @@ void parse_colors(char *ptr)
|
||||
newcolor->next = NULL;
|
||||
newcolor->end = NULL;
|
||||
|
||||
if (tmpsyntax->color == NULL) {
|
||||
tmpsyntax->color = newcolor;
|
||||
if (endcolor == NULL) {
|
||||
endsyntax->color = newcolor;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Starting a new colorstring for fg %d bg %d\n", fg, bg);
|
||||
fprintf(stderr, "Starting a new colorstring for fg %d, bg %d\n", fg, bg);
|
||||
#endif
|
||||
} else {
|
||||
for (tmpcolor = tmpsyntax->color; tmpcolor->next != NULL;
|
||||
tmpcolor = tmpcolor->next)
|
||||
;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Adding new entry for fg %d bg %d\n", fg, bg);
|
||||
fprintf(stderr, "Adding new entry for fg %d, bg %d\n", fg, bg);
|
||||
#endif
|
||||
tmpcolor->next = newcolor;
|
||||
endcolor->next = newcolor;
|
||||
}
|
||||
endcolor = newcolor;
|
||||
}
|
||||
|
||||
if (expectend) {
|
||||
@ -441,63 +450,63 @@ void parse_colors(char *ptr)
|
||||
rcfile_error(N_("\"start=\" requires a corresponding \"end=\""));
|
||||
return;
|
||||
}
|
||||
|
||||
ptr += 4;
|
||||
|
||||
if (*ptr != '"') {
|
||||
rcfile_error(N_("Regex strings must begin and end with a \" character"));
|
||||
continue;
|
||||
}
|
||||
|
||||
ptr++;
|
||||
|
||||
fgstr = ptr;
|
||||
ptr = parse_next_regex(ptr);
|
||||
if (ptr == NULL)
|
||||
break;
|
||||
|
||||
/* If the start regex was invalid, skip past the end regex to
|
||||
* stay in sync. */
|
||||
if (cancelled)
|
||||
continue;
|
||||
|
||||
newcolor->end = (regex_t *)nmalloc(sizeof(regex_t));
|
||||
if (nregcomp(newcolor->end, fgstr, 0) != 0) {
|
||||
if (nregcomp(newcolor->end, fgstr, 0)) {
|
||||
free(newcolor->end);
|
||||
newcolor->end = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* ENABLE_COLOR */
|
||||
|
||||
/* Parse the RC file, once it has been opened successfully */
|
||||
/* Parse the rcfile, once it has been opened successfully. */
|
||||
void parse_rcfile(FILE *rcstream)
|
||||
{
|
||||
char *buf, *ptr, *keyword, *option;
|
||||
int set = 0, i;
|
||||
char *buf = NULL;
|
||||
ssize_t len;
|
||||
size_t n;
|
||||
|
||||
while ((len = getline(&buf, &n, rcstream)) > 0) {
|
||||
char *ptr, *keyword, *option;
|
||||
int set = 0, i;
|
||||
|
||||
/* Ignore the \n. */
|
||||
buf[len - 1] = '\0';
|
||||
|
||||
buf = charalloc(1024);
|
||||
while (fgets(buf, 1023, rcstream) != 0) {
|
||||
lineno++;
|
||||
ptr = buf;
|
||||
while (is_blank_char(*ptr))
|
||||
ptr++;
|
||||
|
||||
if (*ptr == '\n' || *ptr == '\0')
|
||||
/* If we have a blank line or a comment, skip to the next
|
||||
* line. */
|
||||
if (*ptr == '\0' || *ptr == '#')
|
||||
continue;
|
||||
|
||||
if (*ptr == '#') {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%s: Read a comment\n", "parse_rcfile()");
|
||||
#endif
|
||||
continue; /* Skip past commented lines */
|
||||
}
|
||||
|
||||
/* Else skip to the next space */
|
||||
/* Otherwise, skip to the next space. */
|
||||
keyword = ptr;
|
||||
ptr = parse_next_word(ptr);
|
||||
if (ptr == NULL)
|
||||
continue;
|
||||
|
||||
/* Else try to parse the keyword */
|
||||
/* Try to parse the keyword. */
|
||||
if (strcasecmp(keyword, "set") == 0)
|
||||
set = 1;
|
||||
else if (strcasecmp(keyword, "unset") == 0)
|
||||
@ -507,135 +516,124 @@ void parse_rcfile(FILE *rcstream)
|
||||
parse_syntax(ptr);
|
||||
else if (strcasecmp(keyword, "color") == 0)
|
||||
parse_colors(ptr);
|
||||
#endif /* ENABLE_COLOR */
|
||||
else {
|
||||
#endif /* ENABLE_COLOR */
|
||||
else
|
||||
rcfile_error(N_("Command %s not understood"), keyword);
|
||||
|
||||
if (set == 0)
|
||||
continue;
|
||||
|
||||
if (*ptr == '\0') {
|
||||
rcfile_error(N_("Missing flag"));
|
||||
continue;
|
||||
}
|
||||
|
||||
option = ptr;
|
||||
ptr = parse_next_word(ptr);
|
||||
/* We don't care if ptr == NULL, as it should if using proper syntax */
|
||||
|
||||
if (set != 0) {
|
||||
for (i = 0; rcopts[i].name != NULL; i++) {
|
||||
if (strcasecmp(option, rcopts[i].name) == 0) {
|
||||
for (i = 0; rcopts[i].name != NULL; i++) {
|
||||
if (strcasecmp(option, rcopts[i].name) == 0) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%s: Parsing option %s\n",
|
||||
"parse_rcfile()", rcopts[i].name);
|
||||
fprintf(stderr, "parse_rcfile(): name = \"%s\"\n", rcopts[i].name);
|
||||
#endif
|
||||
if (set == 1) {
|
||||
if (strcasecmp(rcopts[i].name, "tabsize") == 0
|
||||
#ifndef DISABLE_OPERATINGDIR
|
||||
|| strcasecmp(rcopts[i].name, "operatingdir") == 0
|
||||
#endif
|
||||
#ifndef DISABLE_WRAPJUSTIFY
|
||||
|| strcasecmp(rcopts[i].name, "fill") == 0
|
||||
#endif
|
||||
#ifndef NANO_SMALL
|
||||
|| strcasecmp(rcopts[i].name, "whitespace") == 0
|
||||
#endif
|
||||
#ifndef DISABLE_JUSTIFY
|
||||
|| strcasecmp(rcopts[i].name, "punct") == 0
|
||||
|| strcasecmp(rcopts[i].name, "brackets") == 0
|
||||
|| strcasecmp(rcopts[i].name, "quotestr") == 0
|
||||
#endif
|
||||
#ifndef NANO_SMALL
|
||||
|| strcasecmp(rcopts[i].name, "backupdir") == 0
|
||||
#endif
|
||||
#ifndef DISABLE_SPELLER
|
||||
|| strcasecmp(rcopts[i].name, "speller") == 0
|
||||
#endif
|
||||
) {
|
||||
if (*ptr == '\n' || *ptr == '\0') {
|
||||
rcfile_error(N_("Option %s requires an argument"), rcopts[i].name);
|
||||
continue;
|
||||
}
|
||||
option = ptr;
|
||||
if (*option == '"')
|
||||
option++;
|
||||
ptr = parse_argument(ptr);
|
||||
if (set == 1) {
|
||||
if (rcopts[i].flag != 0)
|
||||
/* This option has a flag, so it doesn't take an
|
||||
* argument. */
|
||||
SET(rcopts[i].flag);
|
||||
else {
|
||||
/* This option doesn't have a flag, so it takes
|
||||
* an argument. */
|
||||
if (*ptr == '\0') {
|
||||
rcfile_error(N_("Option %s requires an argument"), rcopts[i].name);
|
||||
break;
|
||||
}
|
||||
option = ptr;
|
||||
if (*option == '"')
|
||||
option++;
|
||||
ptr = parse_argument(ptr);
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "option = %s\n", option);
|
||||
fprintf(stderr, "option = \"%s\"\n", option);
|
||||
#endif
|
||||
#ifndef DISABLE_OPERATINGDIR
|
||||
if (strcasecmp(rcopts[i].name, "operatingdir") == 0)
|
||||
operating_dir = mallocstrcpy(NULL, option);
|
||||
else
|
||||
if (strcasecmp(rcopts[i].name, "operatingdir") == 0)
|
||||
operating_dir = mallocstrcpy(NULL, option);
|
||||
else
|
||||
#endif
|
||||
#ifndef DISABLE_WRAPJUSTIFY
|
||||
if (strcasecmp(rcopts[i].name, "fill") == 0) {
|
||||
if (!parse_num(option, &wrap_at)) {
|
||||
rcfile_error(N_("Requested fill size %s invalid"), option);
|
||||
wrap_at = -CHARS_FROM_EOL;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
#ifndef NANO_SMALL
|
||||
if (strcasecmp(rcopts[i].name, "whitespace") == 0) {
|
||||
size_t ws_len;
|
||||
whitespace = mallocstrcpy(NULL, option);
|
||||
ws_len = strlen(whitespace);
|
||||
if (ws_len != 2 || (ws_len == 2 && (is_cntrl_char(whitespace[0]) || is_cntrl_char(whitespace[1])))) {
|
||||
rcfile_error(N_("Two non-control characters required"));
|
||||
free(whitespace);
|
||||
whitespace = NULL;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
#ifndef DISABLE_JUSTIFY
|
||||
if (strcasecmp(rcopts[i].name, "punct") == 0) {
|
||||
punct = mallocstrcpy(NULL, option);
|
||||
if (strchr(punct, '\t') != NULL || strchr(punct, ' ') != NULL) {
|
||||
rcfile_error(N_("Non-tab and non-space characters required"));
|
||||
free(punct);
|
||||
punct = NULL;
|
||||
}
|
||||
} else if (strcasecmp(rcopts[i].name, "brackets") == 0) {
|
||||
brackets = mallocstrcpy(NULL, option);
|
||||
if (strchr(brackets, '\t') != NULL || strchr(brackets, ' ') != NULL) {
|
||||
rcfile_error(N_("Non-tab and non-space characters required"));
|
||||
free(brackets);
|
||||
brackets = NULL;
|
||||
}
|
||||
} else if (strcasecmp(rcopts[i].name, "quotestr") == 0)
|
||||
quotestr = mallocstrcpy(NULL, option);
|
||||
else
|
||||
#endif
|
||||
#ifndef NANO_SMALL
|
||||
if (strcasecmp(rcopts[i].name, "backupdir") == 0)
|
||||
backup_dir = mallocstrcpy(NULL, option);
|
||||
else
|
||||
#endif
|
||||
#ifndef DISABLE_SPELLER
|
||||
if (strcasecmp(rcopts[i].name, "speller") == 0)
|
||||
alt_speller = mallocstrcpy(NULL, option);
|
||||
else
|
||||
#endif
|
||||
if (strcasecmp(rcopts[i].name, "tabsize") == 0) {
|
||||
if (!parse_num(option, &tabsize) || tabsize <= 0) {
|
||||
rcfile_error(N_("Requested tab size %s invalid"), option);
|
||||
tabsize = -1;
|
||||
}
|
||||
if (strcasecmp(rcopts[i].name, "fill") == 0) {
|
||||
if (!parse_num(option, &wrap_at)) {
|
||||
rcfile_error(N_("Requested fill size %s invalid"), option);
|
||||
wrap_at = -CHARS_FROM_EOL;
|
||||
}
|
||||
} else
|
||||
SET(rcopts[i].flag);
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "set flag %ld!\n",
|
||||
rcopts[i].flag);
|
||||
#endif
|
||||
} else {
|
||||
UNSET(rcopts[i].flag);
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "unset flag %ld!\n",
|
||||
rcopts[i].flag);
|
||||
#ifndef NANO_SMALL
|
||||
if (strcasecmp(rcopts[i].name, "whitespace") == 0) {
|
||||
size_t ws_len;
|
||||
whitespace = mallocstrcpy(NULL, option);
|
||||
ws_len = strlen(whitespace);
|
||||
if (ws_len != 2 || (ws_len == 2 && (is_cntrl_char(whitespace[0]) || is_cntrl_char(whitespace[1])))) {
|
||||
rcfile_error(N_("Two non-control characters required"));
|
||||
free(whitespace);
|
||||
whitespace = NULL;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
#ifndef DISABLE_JUSTIFY
|
||||
if (strcasecmp(rcopts[i].name, "punct") == 0) {
|
||||
punct = mallocstrcpy(NULL, option);
|
||||
if (strchr(punct, '\t') != NULL || strchr(punct, ' ') != NULL) {
|
||||
rcfile_error(N_("Non-tab and non-space characters required"));
|
||||
free(punct);
|
||||
punct = NULL;
|
||||
}
|
||||
} else if (strcasecmp(rcopts[i].name, "brackets") == 0) {
|
||||
brackets = mallocstrcpy(NULL, option);
|
||||
if (strchr(brackets, '\t') != NULL || strchr(brackets, ' ') != NULL) {
|
||||
rcfile_error(N_("Non-tab and non-space characters required"));
|
||||
free(brackets);
|
||||
brackets = NULL;
|
||||
}
|
||||
} else if (strcasecmp(rcopts[i].name, "quotestr") == 0)
|
||||
quotestr = mallocstrcpy(NULL, option);
|
||||
else
|
||||
#endif
|
||||
#ifndef NANO_SMALL
|
||||
if (strcasecmp(rcopts[i].name, "backupdir") == 0)
|
||||
backup_dir = mallocstrcpy(NULL, option);
|
||||
else
|
||||
#endif
|
||||
#ifndef DISABLE_SPELLER
|
||||
if (strcasecmp(rcopts[i].name, "speller") == 0)
|
||||
alt_speller = mallocstrcpy(NULL, option);
|
||||
else
|
||||
#endif
|
||||
if (strcasecmp(rcopts[i].name, "tabsize") == 0) {
|
||||
if (!parse_num(option, &tabsize) || tabsize <= 0) {
|
||||
rcfile_error(N_("Requested tab size %s invalid"), option);
|
||||
tabsize = -1;
|
||||
}
|
||||
} else
|
||||
assert(FALSE);
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "flag = %d\n", rcopts[i].flag);
|
||||
#endif
|
||||
} else if (rcopts[i].flag != 0)
|
||||
UNSET(rcopts[i].flag);
|
||||
else
|
||||
rcfile_error(N_("Cannot unset flag %s"), rcopts[i].name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rcopts[i].name == NULL)
|
||||
rcfile_error(N_("Unknown flag %s"), option);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
fclose(rcstream);
|
||||
lineno = 0;
|
||||
|
||||
if (errors) {
|
||||
errors = FALSE;
|
||||
@ -655,52 +653,40 @@ void do_rcfile(void)
|
||||
#ifdef SYSCONFDIR
|
||||
assert(sizeof(SYSCONFDIR) == strlen(SYSCONFDIR) + 1);
|
||||
|
||||
nanorc = SYSCONFDIR "/nanorc";
|
||||
/* Try to open system nanorc */
|
||||
nanorc = mallocstrcpy(nanorc, SYSCONFDIR "/nanorc");
|
||||
/* Try to open the system-wide nanorc. */
|
||||
rcstream = fopen(nanorc, "r");
|
||||
if (rcstream != NULL) {
|
||||
/* Parse it! */
|
||||
if (rcstream != NULL)
|
||||
parse_rcfile(rcstream);
|
||||
fclose(rcstream);
|
||||
}
|
||||
#endif
|
||||
|
||||
lineno = 0;
|
||||
#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
|
||||
/* We've already read SYSCONFDIR/nanorc, if it's there. If we're
|
||||
* root and --disable-wrapping-as-root is used, turn wrapping
|
||||
* off now. */
|
||||
if (geteuid() == NANO_ROOT_UID)
|
||||
SET(NO_WRAP);
|
||||
#endif
|
||||
|
||||
get_homedir();
|
||||
|
||||
if (homedir == NULL) {
|
||||
if (homedir == NULL)
|
||||
rcfile_error(N_("I can't find my home directory! Wah!"));
|
||||
SET(NO_RCFILE);
|
||||
} else {
|
||||
size_t homelen = strlen(homedir);
|
||||
char *nanorcf = charalloc(homelen + 9);
|
||||
|
||||
nanorc = nanorcf;
|
||||
strcpy(nanorcf, homedir);
|
||||
strcpy(nanorcf + homelen, "/.nanorc");
|
||||
|
||||
#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
|
||||
/* If we've already read SYSCONFDIR/nanorc (if it's there), we're
|
||||
root, and --disable-wrapping-as-root is used, turn wrapping off */
|
||||
if (geteuid() == NANO_ROOT_UID)
|
||||
SET(NO_WRAP);
|
||||
#endif
|
||||
else {
|
||||
nanorc = charealloc(nanorc, strlen(homedir) + 9);
|
||||
sprintf(nanorc, "%s/.nanorc", homedir);
|
||||
rcstream = fopen(nanorc, "r");
|
||||
|
||||
if (rcstream == NULL) {
|
||||
/* Don't complain about the file not existing */
|
||||
if (errno != ENOENT) {
|
||||
/* Don't complain about the file's not existing. */
|
||||
if (errno != ENOENT)
|
||||
rcfile_error(N_("Error reading %s: %s"), nanorc, strerror(errno));
|
||||
SET(NO_RCFILE);
|
||||
}
|
||||
} else {
|
||||
} else
|
||||
parse_rcfile(rcstream);
|
||||
fclose(rcstream);
|
||||
}
|
||||
free(nanorcf);
|
||||
}
|
||||
|
||||
lineno = 0;
|
||||
free(nanorc);
|
||||
nanorc = NULL;
|
||||
|
||||
#ifdef ENABLE_COLOR
|
||||
set_colorpairs();
|
||||
|
@ -844,7 +844,7 @@ ssize_t do_replace_loop(const char *needle, const filestruct
|
||||
|
||||
if (!replaceall) {
|
||||
#ifdef ENABLE_COLOR
|
||||
if (ISSET(COLOR_SYNTAX))
|
||||
if (!ISSET(NO_COLOR_SYNTAX))
|
||||
edit_refresh();
|
||||
else
|
||||
#endif
|
||||
|
28
src/winio.c
28
src/winio.c
@ -2658,7 +2658,7 @@ int statusq(bool allow_tabs, const shortcut *s, const char *def,
|
||||
blank_statusbar();
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "I got \"%s\"\n", answer);
|
||||
fprintf(stderr, "answer = \"%s\"\n", answer);
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_TABCOMP
|
||||
@ -3052,7 +3052,7 @@ void edit_add(const filestruct *fileptr, const char *converted, int
|
||||
mvwaddstr(edit, yval, 0, converted);
|
||||
|
||||
#ifdef ENABLE_COLOR
|
||||
if (colorstrings != NULL && ISSET(COLOR_SYNTAX)) {
|
||||
if (colorstrings != NULL && !ISSET(NO_COLOR_SYNTAX)) {
|
||||
const colortype *tmpcolor = colorstrings;
|
||||
|
||||
for (; tmpcolor != NULL; tmpcolor = tmpcolor->next) {
|
||||
@ -3087,17 +3087,19 @@ void edit_add(const filestruct *fileptr, const char *converted, int
|
||||
* unless k is 0. If regexec() returns REG_NOMATCH,
|
||||
* there are no more matches in the line. */
|
||||
if (regexec(&tmpcolor->start, &fileptr->data[k], 1,
|
||||
&startmatch, k == 0 ? 0 :
|
||||
&startmatch, (k == 0) ? 0 :
|
||||
REG_NOTBOL) == REG_NOMATCH)
|
||||
break;
|
||||
/* Translate the match to the beginning of the line. */
|
||||
/* Translate the match to the beginning of the
|
||||
* line. */
|
||||
startmatch.rm_so += k;
|
||||
startmatch.rm_eo += k;
|
||||
if (startmatch.rm_so == startmatch.rm_eo) {
|
||||
startmatch.rm_eo++;
|
||||
statusbar(_("Refusing 0 length regex match"));
|
||||
statusbar(
|
||||
_("Refusing zero-length regex match"));
|
||||
} else if (startmatch.rm_so < endpos &&
|
||||
startmatch.rm_eo > startpos) {
|
||||
startmatch.rm_eo > startpos) {
|
||||
if (startmatch.rm_so <= startpos)
|
||||
x_start = 0;
|
||||
else
|
||||
@ -3157,7 +3159,7 @@ void edit_add(const filestruct *fileptr, const char *converted, int
|
||||
startmatch.rm_eo -= startmatch.rm_so;
|
||||
if (regexec(tmpcolor->end, start_line->data +
|
||||
start_col + startmatch.rm_eo, 0, NULL,
|
||||
start_col + startmatch.rm_eo == 0 ? 0 :
|
||||
(start_col + startmatch.rm_eo == 0) ? 0 :
|
||||
REG_NOTBOL) == REG_NOMATCH)
|
||||
/* No end found after this start. */
|
||||
break;
|
||||
@ -3209,7 +3211,8 @@ void edit_add(const filestruct *fileptr, const char *converted, int
|
||||
while (start_col < endpos) {
|
||||
if (regexec(&tmpcolor->start,
|
||||
fileptr->data + start_col, 1, &startmatch,
|
||||
start_col == 0 ? 0 : REG_NOTBOL) == REG_NOMATCH ||
|
||||
(start_col == 0) ? 0 :
|
||||
REG_NOTBOL) == REG_NOMATCH ||
|
||||
start_col + startmatch.rm_so >= endpos)
|
||||
/* No more starts on this line. */
|
||||
break;
|
||||
@ -3228,7 +3231,8 @@ void edit_add(const filestruct *fileptr, const char *converted, int
|
||||
|
||||
if (regexec(tmpcolor->end,
|
||||
fileptr->data + startmatch.rm_eo, 1, &endmatch,
|
||||
startmatch.rm_eo == 0 ? 0 : REG_NOTBOL) == 0) {
|
||||
(startmatch.rm_eo == 0) ? 0 :
|
||||
REG_NOTBOL) == 0) {
|
||||
/* Translate the end match to be relative to the
|
||||
* beginning of the line. */
|
||||
endmatch.rm_so += startmatch.rm_eo;
|
||||
@ -3268,12 +3272,12 @@ void edit_add(const filestruct *fileptr, const char *converted, int
|
||||
}
|
||||
}
|
||||
start_col = startmatch.rm_so + 1;
|
||||
} /* while start_col < endpos */
|
||||
} /* if (tmp_color->end != NULL) */
|
||||
}
|
||||
}
|
||||
|
||||
wattroff(edit, A_BOLD);
|
||||
wattroff(edit, COLOR_PAIR(tmpcolor->pairnum));
|
||||
} /* for tmpcolor in colorstrings */
|
||||
}
|
||||
}
|
||||
#endif /* ENABLE_COLOR */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user