2001-04-18 04:28:54 +00:00
|
|
|
/* $Id$ */
|
|
|
|
/**************************************************************************
|
2001-05-05 15:02:27 +00:00
|
|
|
* rcfile.c *
|
2001-04-18 04:28:54 +00:00
|
|
|
* *
|
2003-01-15 19:33:27 +00:00
|
|
|
* Copyright (C) 1999-2003 Chris Allegretta *
|
2001-04-18 04:28:54 +00: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 *
|
2001-10-24 11:33:54 +00:00
|
|
|
* the Free Software Foundation; either version 2, or (at your option) *
|
2001-04-18 04:28:54 +00:00
|
|
|
* any later version. *
|
|
|
|
* *
|
|
|
|
* 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. *
|
|
|
|
* *
|
|
|
|
* You should have received a copy of the GNU General Public License *
|
|
|
|
* along with this program; if not, write to the Free Software *
|
|
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
|
|
|
|
* *
|
|
|
|
**************************************************************************/
|
|
|
|
|
2002-09-13 18:14:04 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
2001-04-18 04:28:54 +00:00
|
|
|
#include <stdlib.h>
|
2002-01-22 20:09:20 +00:00
|
|
|
#include <stdarg.h>
|
2001-04-18 04:28:54 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
2002-05-11 03:04:44 +00:00
|
|
|
#include <unistd.h>
|
2001-04-18 04:28:54 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
2003-01-13 01:35:15 +00:00
|
|
|
#include <pwd.h>
|
2002-07-19 01:08:59 +00:00
|
|
|
#include <assert.h>
|
2001-04-18 04:28:54 +00:00
|
|
|
#include "proto.h"
|
|
|
|
#include "nano.h"
|
|
|
|
|
|
|
|
#ifdef ENABLE_NANORC
|
|
|
|
|
2002-09-13 18:14:04 +00:00
|
|
|
const static rcoption rcopts[] = {
|
2002-06-28 22:45:14 +00:00
|
|
|
#ifndef NANO_SMALL
|
2002-01-19 16:52:34 +00:00
|
|
|
{"autoindent", AUTOINDENT},
|
2002-06-28 22:45:14 +00:00
|
|
|
{"backup", BACKUP_FILE},
|
|
|
|
#endif
|
|
|
|
{"const", CONSTUPDATE},
|
|
|
|
#ifndef NANO_SMALL
|
2002-01-19 16:52:34 +00:00
|
|
|
{"cut", CUT_TO_END},
|
2002-06-28 22:45:14 +00:00
|
|
|
#endif
|
2002-07-19 01:08:59 +00:00
|
|
|
#ifndef DISABLE_WRAPJUSTIFY
|
2002-06-28 22:45:14 +00:00
|
|
|
{"fill", 0},
|
2002-07-19 01:08:59 +00:00
|
|
|
#endif
|
2002-06-28 22:45:14 +00:00
|
|
|
{"keypad", ALT_KEYPAD},
|
2002-12-22 16:30:00 +00:00
|
|
|
#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
|
2002-01-19 16:52:34 +00:00
|
|
|
{"mouse", USE_MOUSE},
|
2002-06-28 22:45:14 +00:00
|
|
|
#endif
|
|
|
|
#ifdef ENABLE_MULTIBUFFER
|
|
|
|
{"multibuffer", MULTIBUFFER},
|
|
|
|
#endif
|
|
|
|
#ifndef NANO_SMALL
|
|
|
|
{"noconvert", NO_CONVERT},
|
|
|
|
#endif
|
2002-12-22 16:30:00 +00:00
|
|
|
{"nofollow", NOFOLLOW_SYMLINKS},
|
2002-06-28 22:45:14 +00:00
|
|
|
{"nohelp", NO_HELP},
|
2002-07-19 01:08:59 +00:00
|
|
|
#ifndef DISABLE_WRAPPING
|
2002-06-28 22:45:14 +00:00
|
|
|
{"nowrap", NO_WRAP},
|
2002-07-19 01:08:59 +00:00
|
|
|
#endif
|
2002-06-28 22:45:14 +00:00
|
|
|
#ifndef DISABLE_OPERATINGDIR
|
2002-01-19 16:52:34 +00:00
|
|
|
{"operatingdir", 0},
|
2002-06-28 22:45:14 +00:00
|
|
|
#endif
|
2003-01-13 01:35:15 +00:00
|
|
|
{"preserve", PRESERVE},
|
2002-12-22 16:30:00 +00:00
|
|
|
#ifndef DISABLE_JUSTIFY
|
2002-06-28 22:45:14 +00:00
|
|
|
{"quotestr", 0},
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_REGEX_H
|
|
|
|
{"regexp", USE_REGEXP},
|
|
|
|
#endif
|
|
|
|
#ifndef NANO_SMALL
|
|
|
|
{"smooth", SMOOTHSCROLL},
|
|
|
|
#endif
|
|
|
|
#ifndef DISABLE_SPELLER
|
2002-01-19 16:52:34 +00:00
|
|
|
{"speller", 0},
|
2002-06-28 22:45:14 +00:00
|
|
|
#endif
|
|
|
|
{"suspend", SUSPEND},
|
|
|
|
{"tabsize", 0},
|
2002-01-19 16:52:34 +00:00
|
|
|
{"tempfile", TEMP_OPT},
|
|
|
|
{"view", VIEW_MODE},
|
2003-01-16 23:44:46 +00:00
|
|
|
{"historylog", HISTORYLOG},
|
2002-09-13 18:14:04 +00:00
|
|
|
{NULL, 0}
|
2002-01-19 16:52:34 +00:00
|
|
|
};
|
2001-04-18 04:28:54 +00:00
|
|
|
|
2002-01-18 21:54:35 +00:00
|
|
|
static int errors = 0;
|
|
|
|
static int lineno = 0;
|
|
|
|
static char *nanorc;
|
|
|
|
|
2001-05-05 17:45:54 +00:00
|
|
|
/* We have an error in some part of the rcfile; put it on stderr and
|
2002-07-19 01:08:59 +00:00
|
|
|
make the user hit return to continue starting up nano. */
|
2002-08-21 16:10:37 +00:00
|
|
|
void rcfile_error(const char *msg, ...)
|
2001-04-18 04:28:54 +00:00
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
fprintf(stderr, "\n");
|
2002-03-29 19:41:57 +00:00
|
|
|
if (lineno > 0)
|
|
|
|
fprintf(stderr, _("Error in %s on line %d: "), nanorc, lineno);
|
|
|
|
|
2001-04-18 04:28:54 +00:00
|
|
|
va_start(ap, msg);
|
|
|
|
vfprintf(stderr, msg, ap);
|
|
|
|
va_end(ap);
|
|
|
|
fprintf(stderr, _("\nPress return to continue starting nano\n"));
|
|
|
|
|
2002-01-19 16:52:34 +00:00
|
|
|
while (getchar() != '\n');
|
2001-04-18 04:28:54 +00:00
|
|
|
}
|
|
|
|
|
2002-07-19 01:08:59 +00:00
|
|
|
/* Just print the error (one of many, perhaps) but don't abort, yet. */
|
2002-08-21 16:10:37 +00:00
|
|
|
void rcfile_msg(const char *msg, ...)
|
2001-04-18 04:28:54 +00:00
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
|
2002-01-18 21:54:35 +00:00
|
|
|
if (!errors) {
|
|
|
|
errors = 1;
|
2001-04-18 04:28:54 +00:00
|
|
|
fprintf(stderr, "\n");
|
|
|
|
}
|
|
|
|
va_start(ap, msg);
|
|
|
|
vfprintf(stderr, msg, ap);
|
|
|
|
va_end(ap);
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
}
|
|
|
|
|
2002-07-19 01:08:59 +00:00
|
|
|
/* Parse the next word from the string. Returns NULL if we hit EOL. */
|
2002-08-21 16:10:37 +00:00
|
|
|
char *parse_next_word(char *ptr)
|
2001-04-18 04:28:54 +00:00
|
|
|
{
|
2002-01-19 16:52:34 +00:00
|
|
|
while (*ptr != ' ' && *ptr != '\t' && *ptr != '\n' && *ptr != '\0')
|
|
|
|
ptr++;
|
|
|
|
|
|
|
|
if (*ptr == '\0')
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Null terminate and advance ptr */
|
|
|
|
*ptr++ = 0;
|
|
|
|
|
2002-07-19 01:08:59 +00:00
|
|
|
while (*ptr == ' ' || *ptr == '\t')
|
2002-01-19 16:52:34 +00:00
|
|
|
ptr++;
|
|
|
|
|
|
|
|
return ptr;
|
|
|
|
}
|
2002-01-18 21:54:35 +00:00
|
|
|
|
2002-07-19 01:08:59 +00:00
|
|
|
/* The keywords operatingdir, fill, tabsize, speller, and quotestr take
|
|
|
|
* an argument when set. Among these, operatingdir, speller, and
|
|
|
|
* quotestr 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. */
|
2002-08-21 16:10:37 +00:00
|
|
|
char *parse_argument(char *ptr)
|
|
|
|
{
|
2002-07-19 01:08:59 +00:00
|
|
|
const char *ptr_bak = ptr;
|
|
|
|
char *last_quote = NULL;
|
|
|
|
|
|
|
|
assert(ptr != NULL);
|
|
|
|
|
|
|
|
if (*ptr != '"')
|
|
|
|
return parse_next_word(ptr);
|
|
|
|
|
|
|
|
do {
|
|
|
|
ptr++;
|
|
|
|
if (*ptr == '"')
|
|
|
|
last_quote = ptr;
|
|
|
|
} while (*ptr != '\n' && *ptr != '\0');
|
|
|
|
|
|
|
|
if (last_quote == NULL) {
|
|
|
|
if (*ptr == '\0')
|
|
|
|
ptr = NULL;
|
|
|
|
else
|
|
|
|
*ptr++ = '\0';
|
|
|
|
rcfile_error(_("argument %s has unterminated \""), ptr_bak);
|
|
|
|
} else {
|
|
|
|
*last_quote = '\0';
|
|
|
|
ptr = last_quote + 1;
|
|
|
|
}
|
|
|
|
if (ptr != NULL)
|
|
|
|
while (*ptr == ' ' || *ptr == '\t')
|
|
|
|
ptr++;
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef ENABLE_COLOR
|
|
|
|
|
2002-08-21 16:10:37 +00:00
|
|
|
int colortoint(const char *colorname, int *bright)
|
2001-11-29 02:42:27 +00:00
|
|
|
{
|
|
|
|
int mcolor = 0;
|
|
|
|
|
|
|
|
if (colorname == NULL)
|
|
|
|
return -1;
|
|
|
|
|
2002-07-19 01:08:59 +00:00
|
|
|
if (!strncasecmp(colorname, "bright", 6)) {
|
2001-12-02 04:55:44 +00:00
|
|
|
*bright = 1;
|
2001-11-29 02:42:27 +00:00
|
|
|
colorname += 6;
|
|
|
|
}
|
2002-01-19 16:52:34 +00:00
|
|
|
|
2001-11-29 02:42:27 +00:00
|
|
|
if (!strcasecmp(colorname, "green"))
|
2002-07-19 01:08:59 +00:00
|
|
|
mcolor = COLOR_GREEN;
|
2001-11-29 02:42:27 +00:00
|
|
|
else if (!strcasecmp(colorname, "red"))
|
2002-07-19 01:08:59 +00:00
|
|
|
mcolor = COLOR_RED;
|
2001-11-29 02:42:27 +00:00
|
|
|
else if (!strcasecmp(colorname, "blue"))
|
2002-07-19 01:08:59 +00:00
|
|
|
mcolor = COLOR_BLUE;
|
2001-11-29 02:42:27 +00:00
|
|
|
else if (!strcasecmp(colorname, "white"))
|
2002-07-19 01:08:59 +00:00
|
|
|
mcolor = COLOR_WHITE;
|
2001-11-29 02:42:27 +00:00
|
|
|
else if (!strcasecmp(colorname, "yellow"))
|
2002-07-19 01:08:59 +00:00
|
|
|
mcolor = COLOR_YELLOW;
|
2001-11-29 02:42:27 +00:00
|
|
|
else if (!strcasecmp(colorname, "cyan"))
|
2002-07-19 01:08:59 +00:00
|
|
|
mcolor = COLOR_CYAN;
|
2001-11-29 02:42:27 +00:00
|
|
|
else if (!strcasecmp(colorname, "magenta"))
|
2002-07-19 01:08:59 +00:00
|
|
|
mcolor = COLOR_MAGENTA;
|
2001-11-29 02:42:27 +00:00
|
|
|
else if (!strcasecmp(colorname, "black"))
|
2002-07-19 01:08:59 +00:00
|
|
|
mcolor = COLOR_BLACK;
|
2001-11-29 02:42:27 +00:00
|
|
|
else {
|
2002-01-19 16:52:34 +00:00
|
|
|
rcfile_error(_("color %s not understood.\n"
|
|
|
|
"Valid colors are \"green\", \"red\", \"blue\", \n"
|
|
|
|
"\"white\", \"yellow\", \"cyan\", \"magenta\" and \n"
|
2003-02-07 00:02:00 +00:00
|
|
|
"\"black\", with the optional prefix \"bright\".\n"),
|
|
|
|
colorname);
|
|
|
|
mcolor = -1;
|
2001-11-29 02:42:27 +00:00
|
|
|
}
|
|
|
|
return mcolor;
|
|
|
|
}
|
|
|
|
|
2002-09-06 20:35:28 +00:00
|
|
|
char *parse_next_regex(char *ptr)
|
|
|
|
{
|
|
|
|
while ((*ptr != '"' || (*(ptr + 1) != ' ' && *(ptr + 1) != '\n'))
|
|
|
|
&& *ptr != '\n' && *ptr != '\0')
|
|
|
|
ptr++;
|
|
|
|
|
|
|
|
if (*ptr == '\0')
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Null terminate and advance ptr */
|
|
|
|
*ptr++ = '\0';
|
|
|
|
|
|
|
|
while (*ptr == ' ' || *ptr == '\t')
|
|
|
|
ptr++;
|
|
|
|
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
2003-02-03 02:56:44 +00:00
|
|
|
/* Compile the regular expression regex to preg. Returns FALSE on success,
|
|
|
|
TRUE if the expression is invalid. */
|
|
|
|
int nregcomp(regex_t *preg, const char *regex, int flags)
|
|
|
|
{
|
|
|
|
int rc = regcomp(preg, regex, REG_EXTENDED | flags);
|
|
|
|
|
|
|
|
if (rc != 0) {
|
|
|
|
size_t len = regerror(rc, preg, NULL, 0);
|
|
|
|
char *str = charalloc(len);
|
|
|
|
|
|
|
|
regerror(rc, preg, str, len);
|
|
|
|
rcfile_error(_("Bad regex \"%s\": %s"), regex, str);
|
|
|
|
free(str);
|
|
|
|
}
|
|
|
|
return rc != 0;
|
|
|
|
}
|
|
|
|
|
2002-08-21 16:10:37 +00:00
|
|
|
void parse_syntax(char *ptr)
|
2002-05-04 03:47:33 +00:00
|
|
|
{
|
|
|
|
syntaxtype *tmpsyntax = NULL;
|
2002-07-19 01:08:59 +00:00
|
|
|
const char *fileregptr = NULL, *nameptr = NULL;
|
2003-02-03 02:56:44 +00:00
|
|
|
exttype *endext = NULL;
|
|
|
|
/* The end of the extensions list for this syntax. */
|
2002-05-04 03:47:33 +00:00
|
|
|
|
|
|
|
while (*ptr == ' ')
|
|
|
|
ptr++;
|
|
|
|
|
|
|
|
if (*ptr == '\n' || *ptr == '\0')
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (*ptr != '"') {
|
|
|
|
rcfile_error(_("regex strings must begin and end with a \" character\n"));
|
2002-05-04 04:23:30 +00:00
|
|
|
return;
|
2002-05-04 03:47:33 +00:00
|
|
|
}
|
|
|
|
ptr++;
|
|
|
|
|
|
|
|
nameptr = ptr;
|
|
|
|
ptr = parse_next_regex(ptr);
|
|
|
|
|
|
|
|
if (ptr == NULL) {
|
|
|
|
rcfile_error(_("Missing syntax name"));
|
2002-05-04 04:23:30 +00:00
|
|
|
return;
|
2002-05-04 03:47:33 +00:00
|
|
|
}
|
|
|
|
|
2002-07-19 01:08:59 +00:00
|
|
|
if (syntaxes == NULL) {
|
|
|
|
syntaxes = (syntaxtype *)nmalloc(sizeof(syntaxtype));
|
|
|
|
tmpsyntax = syntaxes;
|
2002-10-13 18:43:45 +00:00
|
|
|
SET(COLOR_SYNTAX);
|
2002-07-19 01:08:59 +00:00
|
|
|
} else {
|
|
|
|
for (tmpsyntax = syntaxes; tmpsyntax->next != NULL;
|
|
|
|
tmpsyntax = tmpsyntax->next)
|
|
|
|
;
|
|
|
|
tmpsyntax->next = (syntaxtype *)nmalloc(sizeof(syntaxtype));
|
|
|
|
tmpsyntax = tmpsyntax->next;
|
2002-05-04 03:47:33 +00:00
|
|
|
#ifdef DEBUG
|
2002-07-19 01:08:59 +00:00
|
|
|
fprintf(stderr, _("Adding new syntax after 1st\n"));
|
2002-05-04 03:47:33 +00:00
|
|
|
#endif
|
2002-07-19 01:08:59 +00:00
|
|
|
}
|
|
|
|
tmpsyntax->desc = mallocstrcpy(NULL, nameptr);
|
|
|
|
tmpsyntax->color = NULL;
|
|
|
|
tmpsyntax->extensions = NULL;
|
|
|
|
tmpsyntax->next = NULL;
|
2002-05-04 03:47:33 +00:00
|
|
|
#ifdef DEBUG
|
2002-07-19 01:08:59 +00:00
|
|
|
fprintf(stderr, _("Starting a new syntax type\n"));
|
|
|
|
fprintf(stderr, "string val=%s\n", nameptr);
|
2002-05-04 03:47:33 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Now load in the extensions to their part of the struct */
|
|
|
|
while (*ptr != '\n' && *ptr != '\0') {
|
2003-02-03 02:56:44 +00:00
|
|
|
exttype *newext;
|
|
|
|
/* The new extension structure. */
|
|
|
|
|
2002-05-04 03:47:33 +00:00
|
|
|
while (*ptr != '"' && *ptr != '\n' && *ptr != '\0')
|
|
|
|
ptr++;
|
|
|
|
|
|
|
|
if (*ptr == '\n' || *ptr == '\0')
|
|
|
|
return;
|
|
|
|
ptr++;
|
|
|
|
|
|
|
|
fileregptr = ptr;
|
|
|
|
ptr = parse_next_regex(ptr);
|
|
|
|
|
2003-02-03 02:56:44 +00:00
|
|
|
newext = (exttype *)nmalloc(sizeof(exttype));
|
|
|
|
if (nregcomp(&newext->val, fileregptr, REG_NOSUB))
|
|
|
|
free(newext);
|
|
|
|
else {
|
|
|
|
if (endext == NULL)
|
|
|
|
tmpsyntax->extensions = newext;
|
|
|
|
else
|
|
|
|
endext->next = newext;
|
|
|
|
endext = newext;
|
|
|
|
endext->next = NULL;
|
2002-05-04 03:47:33 +00:00
|
|
|
}
|
2002-06-28 22:45:14 +00:00
|
|
|
}
|
2002-05-04 03:47:33 +00:00
|
|
|
}
|
|
|
|
|
2001-11-29 02:42:27 +00:00
|
|
|
/* Parse the color stuff into the colorstrings array */
|
2002-08-21 16:10:37 +00:00
|
|
|
void parse_colors(char *ptr)
|
2001-11-29 02:42:27 +00:00
|
|
|
{
|
2002-01-19 16:52:34 +00:00
|
|
|
int fg, bg, bright = 0;
|
|
|
|
int expectend = 0; /* Do we expect an end= line? */
|
2002-07-19 01:08:59 +00:00
|
|
|
char *fgstr;
|
2001-11-29 02:42:27 +00:00
|
|
|
colortype *tmpcolor = NULL;
|
2002-05-04 03:47:33 +00:00
|
|
|
syntaxtype *tmpsyntax = NULL;
|
2001-11-29 02:42:27 +00:00
|
|
|
|
|
|
|
fgstr = ptr;
|
|
|
|
ptr = parse_next_word(ptr);
|
|
|
|
|
|
|
|
if (ptr == NULL) {
|
2002-01-18 21:54:35 +00:00
|
|
|
rcfile_error(_("Missing color name"));
|
2002-05-04 04:23:30 +00:00
|
|
|
return;
|
2001-11-29 02:42:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (strstr(fgstr, ",")) {
|
|
|
|
strtok(fgstr, ",");
|
2002-07-19 01:08:59 +00:00
|
|
|
bg = colortoint(strtok(NULL, ","), &bright);
|
2001-11-29 02:42:27 +00:00
|
|
|
} else
|
2002-07-19 01:08:59 +00:00
|
|
|
bg = -1;
|
2001-11-29 02:42:27 +00:00
|
|
|
|
2002-01-18 21:54:35 +00:00
|
|
|
fg = colortoint(fgstr, &bright);
|
2001-11-29 02:42:27 +00:00
|
|
|
|
2003-02-07 00:19:05 +00:00
|
|
|
/* Don't try and parse screwed up fg colors */
|
|
|
|
if (fg == -1)
|
|
|
|
return;
|
|
|
|
|
2002-05-04 03:47:33 +00:00
|
|
|
if (syntaxes == NULL) {
|
|
|
|
rcfile_error(_("Cannot add a color directive without a syntax line"));
|
2002-05-04 04:23:30 +00:00
|
|
|
return;
|
2002-05-04 03:47:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (tmpsyntax = syntaxes; tmpsyntax->next != NULL;
|
|
|
|
tmpsyntax = tmpsyntax->next)
|
|
|
|
;
|
|
|
|
|
2001-11-29 02:42:27 +00:00
|
|
|
/* Now the fun part, start adding regexps to individual strings
|
2002-01-19 16:52:34 +00:00
|
|
|
in the colorstrings array, woo! */
|
2001-11-29 02:42:27 +00:00
|
|
|
|
2002-01-19 16:52:34 +00:00
|
|
|
while (*ptr != '\0') {
|
2003-02-03 02:56:44 +00:00
|
|
|
colortype *newcolor;
|
|
|
|
/* The new color structure. */
|
|
|
|
int cancelled = 0;
|
|
|
|
/* The start expression was bad. */
|
|
|
|
|
2002-01-19 16:52:34 +00:00
|
|
|
while (*ptr == ' ')
|
|
|
|
ptr++;
|
|
|
|
|
|
|
|
if (*ptr == '\n' || *ptr == '\0')
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (!strncasecmp(ptr, "start=", 6)) {
|
|
|
|
ptr += 6;
|
|
|
|
expectend = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*ptr != '"') {
|
|
|
|
rcfile_error(_("regex strings must begin and end with a \" character\n"));
|
2002-09-18 00:28:57 +00:00
|
|
|
ptr = parse_next_regex(ptr);
|
2002-01-19 16:52:34 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ptr++;
|
2002-01-18 21:54:35 +00:00
|
|
|
|
2003-02-03 02:56:44 +00:00
|
|
|
newcolor = (colortype *)nmalloc(sizeof(colortype));
|
|
|
|
fgstr = ptr;
|
|
|
|
ptr = parse_next_regex(ptr);
|
|
|
|
if (nregcomp(&newcolor->start, fgstr, 0)) {
|
|
|
|
free(newcolor);
|
|
|
|
cancelled = 1;
|
2002-01-19 16:52:34 +00:00
|
|
|
} else {
|
2003-02-03 02:56:44 +00:00
|
|
|
newcolor->fg = fg;
|
|
|
|
newcolor->bg = bg;
|
|
|
|
newcolor->bright = bright;
|
|
|
|
newcolor->next = NULL;
|
|
|
|
newcolor->end = NULL;
|
|
|
|
|
|
|
|
if (tmpsyntax->color == NULL) {
|
|
|
|
tmpsyntax->color = newcolor;
|
2001-11-29 03:49:09 +00:00
|
|
|
#ifdef DEBUG
|
2003-02-03 02:56:44 +00:00
|
|
|
fprintf(stderr, _("Starting a new colorstring for fg %d bg %d\n"),
|
|
|
|
fg, bg);
|
2001-11-29 03:49:09 +00:00
|
|
|
#endif
|
2003-02-03 02:56:44 +00:00
|
|
|
} else {
|
|
|
|
for (tmpcolor = tmpsyntax->color; tmpcolor->next != NULL;
|
|
|
|
tmpcolor = tmpcolor->next)
|
|
|
|
;
|
2002-07-19 01:08:59 +00:00
|
|
|
#ifdef DEBUG
|
2003-02-03 02:56:44 +00:00
|
|
|
fprintf(stderr, _("Adding new entry for fg %d bg %d\n"), fg, bg);
|
2002-07-19 01:08:59 +00:00
|
|
|
#endif
|
2003-02-03 02:56:44 +00:00
|
|
|
tmpcolor->next = newcolor;
|
|
|
|
}
|
|
|
|
}
|
2002-07-19 01:08:59 +00:00
|
|
|
|
2003-02-03 02:56:44 +00:00
|
|
|
if (expectend) {
|
2002-01-19 16:52:34 +00:00
|
|
|
if (ptr == NULL || strncasecmp(ptr, "end=", 4)) {
|
|
|
|
rcfile_error(_
|
2002-12-22 16:30:00 +00:00
|
|
|
("\"start=\" requires a corresponding \"end=\""));
|
2002-01-19 16:52:34 +00:00
|
|
|
return;
|
|
|
|
}
|
2002-01-18 21:54:35 +00:00
|
|
|
|
2002-01-19 16:52:34 +00:00
|
|
|
ptr += 4;
|
2002-01-18 21:54:35 +00:00
|
|
|
|
2002-01-19 16:52:34 +00:00
|
|
|
if (*ptr != '"') {
|
|
|
|
rcfile_error(_
|
|
|
|
("regex strings must begin and end with a \" character\n"));
|
|
|
|
continue;
|
2001-11-29 02:42:27 +00:00
|
|
|
}
|
|
|
|
ptr++;
|
|
|
|
|
2003-02-03 02:56:44 +00:00
|
|
|
fgstr = ptr;
|
2002-01-19 16:52:34 +00:00
|
|
|
ptr = parse_next_regex(ptr);
|
2003-02-03 02:56:44 +00:00
|
|
|
|
|
|
|
/* 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)) {
|
|
|
|
free(newcolor->end);
|
|
|
|
newcolor->end = NULL;
|
|
|
|
}
|
2002-07-19 01:08:59 +00:00
|
|
|
}
|
2002-01-19 16:52:34 +00:00
|
|
|
}
|
2001-11-29 02:42:27 +00:00
|
|
|
}
|
2002-06-28 22:45:14 +00:00
|
|
|
|
|
|
|
#endif /* ENABLE_COLOR */
|
2001-11-29 02:42:27 +00:00
|
|
|
|
2001-04-18 04:28:54 +00:00
|
|
|
/* Parse the RC file, once it has been opened successfully */
|
2002-08-21 16:10:37 +00:00
|
|
|
void parse_rcfile(FILE *rcstream)
|
2001-04-18 04:28:54 +00:00
|
|
|
{
|
|
|
|
char *buf, *ptr, *keyword, *option;
|
2002-03-07 00:46:17 +00:00
|
|
|
int set = 0, i, j;
|
2001-04-18 04:28:54 +00:00
|
|
|
|
2001-05-18 04:44:16 +00:00
|
|
|
buf = charalloc(1024);
|
2002-07-19 01:08:59 +00:00
|
|
|
while (fgets(buf, 1023, rcstream) != 0) {
|
2001-04-18 04:28:54 +00:00
|
|
|
lineno++;
|
|
|
|
ptr = buf;
|
2002-07-19 01:08:59 +00:00
|
|
|
while (*ptr == ' ' || *ptr == '\t')
|
2001-04-18 04:28:54 +00:00
|
|
|
ptr++;
|
|
|
|
|
|
|
|
if (*ptr == '\n' || *ptr == '\0')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (*ptr == '#') {
|
|
|
|
#ifdef DEBUG
|
2003-01-23 04:27:23 +00:00
|
|
|
fprintf(stderr, _("%s: Read a comment\n"), "parse_rcfile()");
|
2001-04-18 04:28:54 +00:00
|
|
|
#endif
|
2002-01-19 16:52:34 +00:00
|
|
|
continue; /* Skip past commented lines */
|
2001-04-18 04:28:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Else skip to the next space */
|
|
|
|
keyword = ptr;
|
|
|
|
ptr = parse_next_word(ptr);
|
2002-12-22 16:30:00 +00:00
|
|
|
if (ptr == NULL)
|
2001-04-18 04:28:54 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Else try to parse the keyword */
|
|
|
|
if (!strcasecmp(keyword, "set"))
|
|
|
|
set = 1;
|
|
|
|
else if (!strcasecmp(keyword, "unset"))
|
|
|
|
set = -1;
|
2001-11-29 02:42:27 +00:00
|
|
|
#ifdef ENABLE_COLOR
|
2002-05-04 03:47:33 +00:00
|
|
|
else if (!strcasecmp(keyword, "syntax"))
|
2002-07-19 01:08:59 +00:00
|
|
|
parse_syntax(ptr);
|
2001-11-29 02:42:27 +00:00
|
|
|
else if (!strcasecmp(keyword, "color"))
|
2002-07-19 01:08:59 +00:00
|
|
|
parse_colors(ptr);
|
2002-01-19 16:52:34 +00:00
|
|
|
#endif /* ENABLE_COLOR */
|
2001-04-18 04:28:54 +00:00
|
|
|
else {
|
2002-01-18 21:54:35 +00:00
|
|
|
rcfile_msg(_("command %s not understood"), keyword);
|
2001-04-18 04:28:54 +00:00
|
|
|
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) {
|
2002-09-13 18:14:04 +00:00
|
|
|
for (i = 0; rcopts[i].name != NULL; i++) {
|
2002-01-19 16:52:34 +00:00
|
|
|
if (!strcasecmp(option, rcopts[i].name)) {
|
2001-04-18 04:28:54 +00:00
|
|
|
#ifdef DEBUG
|
2003-01-23 04:27:23 +00:00
|
|
|
fprintf(stderr, _("%s: Parsing option %s\n"),
|
|
|
|
"parse_rcfile()", rcopts[i].name);
|
2001-04-18 04:28:54 +00:00
|
|
|
#endif
|
2002-12-22 16:30:00 +00:00
|
|
|
if (set == 1) {
|
2002-07-19 01:08:59 +00:00
|
|
|
if (!strcasecmp(rcopts[i].name, "tabsize")
|
|
|
|
#ifndef DISABLE_OPERATINGDIR
|
|
|
|
|| !strcasecmp(rcopts[i].name, "operatingdir")
|
|
|
|
#endif
|
2001-05-21 12:56:25 +00:00
|
|
|
#ifndef DISABLE_WRAPJUSTIFY
|
2002-07-19 01:08:59 +00:00
|
|
|
|| !strcasecmp(rcopts[i].name, "fill")
|
2001-05-21 12:56:25 +00:00
|
|
|
#endif
|
2002-03-03 22:52:52 +00:00
|
|
|
#ifndef DISABLE_JUSTIFY
|
2002-07-19 01:08:59 +00:00
|
|
|
|| !strcasecmp(rcopts[i].name, "quotestr")
|
2002-03-03 22:52:52 +00:00
|
|
|
#endif
|
2001-05-21 12:56:25 +00:00
|
|
|
#ifndef DISABLE_SPELLER
|
2002-07-19 01:08:59 +00:00
|
|
|
|| !strcasecmp(rcopts[i].name, "speller")
|
2001-05-21 12:56:25 +00:00
|
|
|
#endif
|
2002-07-19 01:08:59 +00:00
|
|
|
) {
|
2001-04-18 04:28:54 +00:00
|
|
|
if (*ptr == '\n' || *ptr == '\0') {
|
2002-01-19 16:52:34 +00:00
|
|
|
rcfile_error(_
|
|
|
|
("option %s requires an argument"),
|
|
|
|
rcopts[i].name);
|
2001-04-18 04:28:54 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
option = ptr;
|
2002-07-19 01:08:59 +00:00
|
|
|
if (*option == '"')
|
|
|
|
option++;
|
|
|
|
ptr = parse_argument(ptr);
|
|
|
|
#ifdef DEBUG
|
|
|
|
fprintf(stderr, "option = %s\n", option);
|
|
|
|
#endif
|
|
|
|
#ifndef DISABLE_OPERATINGDIR
|
|
|
|
if (!strcasecmp(rcopts[i].name, "operatingdir"))
|
|
|
|
operating_dir = mallocstrcpy(NULL, option);
|
|
|
|
else
|
|
|
|
#endif
|
2001-05-21 12:56:25 +00:00
|
|
|
#ifndef DISABLE_WRAPJUSTIFY
|
2002-07-19 01:08:59 +00:00
|
|
|
if (!strcasecmp(rcopts[i].name, "fill")) {
|
|
|
|
char *first_error;
|
|
|
|
|
2003-01-13 01:35:15 +00:00
|
|
|
/* Using strtol() instead of atoi() lets
|
|
|
|
* us accept 0 while checking other
|
2002-07-19 01:08:59 +00:00
|
|
|
* errors. */
|
|
|
|
j = (int)strtol(option, &first_error, 10);
|
|
|
|
if (errno == ERANGE || *option == '\0' || *first_error != '\0')
|
|
|
|
rcfile_error(_("requested fill size %d invalid"),
|
2002-03-07 00:46:17 +00:00
|
|
|
j);
|
2002-07-19 01:08:59 +00:00
|
|
|
else
|
|
|
|
wrap_at = j;
|
2002-01-19 16:52:34 +00:00
|
|
|
} else
|
2002-07-19 01:08:59 +00:00
|
|
|
#endif
|
2002-03-03 22:52:52 +00:00
|
|
|
#ifndef DISABLE_JUSTIFY
|
2002-07-19 01:08:59 +00:00
|
|
|
if (!strcasecmp(rcopts[i].name, "quotestr"))
|
|
|
|
quotestr = mallocstrcpy(NULL, option);
|
|
|
|
else
|
2002-03-03 22:52:52 +00:00
|
|
|
#endif
|
2001-05-21 12:56:25 +00:00
|
|
|
#ifndef DISABLE_SPELLER
|
2002-07-19 01:08:59 +00:00
|
|
|
if (!strcasecmp(rcopts[i].name, "speller"))
|
|
|
|
alt_speller = mallocstrcpy(NULL, option);
|
|
|
|
else
|
2001-05-21 12:56:25 +00:00
|
|
|
#endif
|
2002-07-19 01:08:59 +00:00
|
|
|
{
|
|
|
|
char *first_error;
|
|
|
|
|
|
|
|
/* Using strtol instead of atoi lets us
|
|
|
|
* accept 0 while checking other
|
|
|
|
* errors. */
|
|
|
|
j = (int)strtol(option, &first_error, 10);
|
|
|
|
if (errno == ERANGE || *option == '\0' || *first_error != '\0')
|
|
|
|
rcfile_error(_("requested tab size %d invalid"),
|
|
|
|
j);
|
|
|
|
else
|
|
|
|
tabsize = j;
|
2001-04-18 04:28:54 +00:00
|
|
|
}
|
2002-01-19 16:52:34 +00:00
|
|
|
} else
|
2001-04-18 04:28:54 +00:00
|
|
|
SET(rcopts[i].flag);
|
|
|
|
#ifdef DEBUG
|
2002-01-19 16:52:34 +00:00
|
|
|
fprintf(stderr, _("set flag %d!\n"),
|
|
|
|
rcopts[i].flag);
|
2001-04-18 04:28:54 +00:00
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
UNSET(rcopts[i].flag);
|
|
|
|
#ifdef DEBUG
|
2002-01-19 16:52:34 +00:00
|
|
|
fprintf(stderr, _("unset flag %d!\n"),
|
|
|
|
rcopts[i].flag);
|
2001-04-18 04:28:54 +00:00
|
|
|
#endif
|
2002-01-19 16:52:34 +00:00
|
|
|
}
|
2001-04-18 04:28:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-07-19 01:08:59 +00:00
|
|
|
free(buf);
|
2001-04-18 04:28:54 +00:00
|
|
|
if (errors)
|
|
|
|
rcfile_error(_("Errors found in .nanorc file"));
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The main rc file function, tries to open the rc file */
|
|
|
|
void do_rcfile(void)
|
|
|
|
{
|
|
|
|
FILE *rcstream;
|
2002-07-19 01:08:59 +00:00
|
|
|
const struct passwd *userage;
|
|
|
|
uid_t euid = geteuid();
|
2003-02-13 22:18:24 +00:00
|
|
|
char *homenv = getenv("HOME");
|
2001-04-18 04:28:54 +00:00
|
|
|
|
2002-07-19 01:08:59 +00:00
|
|
|
#ifdef SYSCONFDIR
|
|
|
|
assert(sizeof(SYSCONFDIR) == strlen(SYSCONFDIR) + 1);
|
|
|
|
nanorc = charalloc(sizeof(SYSCONFDIR) + 7);
|
2002-02-16 20:34:57 +00:00
|
|
|
sprintf(nanorc, "%s/nanorc", SYSCONFDIR);
|
|
|
|
/* Try to open system nanorc */
|
2002-07-19 01:08:59 +00:00
|
|
|
if ((rcstream = fopen(nanorc, "r")) != NULL) {
|
|
|
|
/* Parse it! */
|
|
|
|
parse_rcfile(rcstream);
|
|
|
|
fclose(rcstream);
|
|
|
|
}
|
|
|
|
#endif
|
2002-02-16 20:34:57 +00:00
|
|
|
|
2002-03-29 19:41:57 +00:00
|
|
|
lineno = 0;
|
2002-05-11 03:04:44 +00:00
|
|
|
|
2003-02-13 03:36:15 +00:00
|
|
|
/* Rely on $HOME, fall back on getpwuid() */
|
2003-02-13 22:18:24 +00:00
|
|
|
if (homenv != NULL) {
|
2003-06-14 20:41:34 +00:00
|
|
|
nanorc = charealloc(nanorc, strlen(homenv) + 10);
|
2003-02-13 22:18:24 +00:00
|
|
|
sprintf(nanorc, "%s/.nanorc", homenv);
|
2003-01-05 20:41:21 +00:00
|
|
|
} else {
|
2003-02-13 03:36:15 +00:00
|
|
|
userage = getpwuid(euid);
|
|
|
|
endpwent();
|
|
|
|
|
|
|
|
if (userage == NULL) {
|
|
|
|
rcfile_error(_("I can't find my home directory! Wah!"));
|
|
|
|
SET(NO_RCFILE);
|
|
|
|
} else {
|
2003-06-14 20:41:34 +00:00
|
|
|
nanorc = charealloc(nanorc, strlen(userage->pw_dir) + 9);
|
2003-02-13 03:36:15 +00:00
|
|
|
sprintf(nanorc, "%s/.nanorc", userage->pw_dir);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ISSET(NO_RCFILE)) {
|
2002-07-19 01:08:59 +00:00
|
|
|
|
2002-10-25 16:08:53 +00:00
|
|
|
#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 (euid == 0)
|
|
|
|
SET(NO_WRAP);
|
|
|
|
#endif
|
2002-07-19 01:08:59 +00:00
|
|
|
if ((rcstream = fopen(nanorc, "r")) == NULL) {
|
|
|
|
/* Don't complain about the file not existing */
|
2003-01-05 20:41:21 +00:00
|
|
|
if (errno != ENOENT) {
|
2002-07-19 01:08:59 +00:00
|
|
|
rcfile_error(_("Unable to open ~/.nanorc file, %s"),
|
|
|
|
strerror(errno));
|
2003-01-05 20:41:21 +00:00
|
|
|
SET(NO_RCFILE);
|
|
|
|
}
|
2002-07-19 01:08:59 +00:00
|
|
|
} else {
|
|
|
|
parse_rcfile(rcstream);
|
|
|
|
fclose(rcstream);
|
|
|
|
}
|
2001-04-18 04:28:54 +00:00
|
|
|
}
|
2003-03-11 03:50:40 +00:00
|
|
|
lineno = 0;
|
2001-04-18 04:28:54 +00:00
|
|
|
|
2002-07-19 01:08:59 +00:00
|
|
|
free(nanorc);
|
2002-09-27 14:21:59 +00:00
|
|
|
#ifdef ENABLE_COLOR
|
|
|
|
set_colorpairs();
|
|
|
|
#endif
|
2001-04-18 04:28:54 +00:00
|
|
|
}
|
|
|
|
|
2002-06-28 22:45:14 +00:00
|
|
|
#endif /* ENABLE_NANORC */
|