diff -ur nano-1.2.2/color.c nano-1.2.2-fixed/color.c --- nano-1.2.2/color.c 2003-08-05 21:15:15.000000000 -0600 +++ nano-1.2.2-fixed/color.c 2003-09-10 02:52:15.000000000 -0600 @@ -40,11 +40,11 @@ const syntaxtype *this_syntax = syntaxes; for(; this_syntax != NULL; this_syntax = this_syntax->next) { - colortype *this_color = this_syntax->color; + colortype *this_color = this_syntax->colors; int color_pair = 1; for(; this_color != NULL; this_color = this_color->next) { - const colortype *beforenow = this_syntax->color; + const colortype *beforenow = this_syntax->colors; for(; beforenow != NULL && beforenow != this_color && (beforenow->fg != this_color->fg || @@ -101,30 +101,75 @@ /* Update the color information based on the current filename. */ void update_color(void) { - const syntaxtype *tmpsyntax; + syntaxtype *tmpsyntax; colorstrings = NULL; - 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 */ - if (!regexec(&e->val, filename, 0, NULL, 0)) - colorstrings = tmpsyntax->color; + /* the syntax override would apply to all files opened in this process */ + /* use the syntax override when given */ + if (syntaxstr != NULL) { + for (tmpsyntax = syntaxes; tmpsyntax != NULL; tmpsyntax = tmpsyntax->next) { + if (!strcasecmp(tmpsyntax->desc, syntaxstr)) { + colorstrings = tmpsyntax->colors; + break; + } + } + } + + /* compare filename to each syntax extension */ + if (colorstrings == NULL) { + for (tmpsyntax = syntaxes; tmpsyntax != NULL; tmpsyntax = tmpsyntax->next) { + exttype *e; + + for (e = tmpsyntax->extensions; e != NULL; e = e->next) { + if (tmpsyntax->desc != NULL) { + regex_t preg; + + /* should file extensions be case-insensitive? */ + + regcomp(&preg, e->ext_regex, REG_EXTENDED | REG_NOSUB); + + /* Set colorstrings if we matched the extension regex */ + if (!regexec(&preg, filename, 0, NULL, 0)) { + colorstrings = tmpsyntax->colors; + regfree(&preg); + break; + } + regfree(&preg); + } + } if (colorstrings != NULL) break; } } - /* if we haven't found a match, use the override string */ - if (colorstrings == NULL && syntaxstr != NULL) { - for (tmpsyntax = syntaxes; tmpsyntax != NULL; - tmpsyntax = tmpsyntax->next) { - if (!strcasecmp(tmpsyntax->desc, syntaxstr)) - colorstrings = tmpsyntax->color; + /* is there a default syntax? */ + if (colorstrings == NULL) + for(tmpsyntax = syntaxes; tmpsyntax != NULL; tmpsyntax = tmpsyntax->next) + if (tmpsyntax->desc == NULL) { + colorstrings = tmpsyntax->colors; + break; + } + + /* compile regular expressions for each color in the current syntax */ + /* each color string is freed after being compiled */ + if (tmpsyntax != NULL && !tmpsyntax->compiled) { + colortype *c; + + for (c = tmpsyntax->colors; c != NULL; c = c->next) { + regcomp(&c->start, c->start_regex, (c->flags.insensitive ? REG_ICASE : 0) | REG_EXTENDED); + free(c->start_regex); + if (c->end_regex != NULL) { + c->end = (regex_t *)nmalloc(sizeof(regex_t)); + regcomp(c->end, c->end_regex, (c->flags.insensitive ? REG_ICASE : 0) | REG_EXTENDED); + free(c->end_regex); + } } + + tmpsyntax->compiled = 1; } + do_colorinit(); } diff -ur nano-1.2.2/files.c nano-1.2.2-fixed/files.c --- nano-1.2.2/files.c 2003-08-05 21:15:15.000000000 -0600 +++ nano-1.2.2-fixed/files.c 2003-09-09 23:26:15.000000000 -0600 @@ -1009,7 +1009,7 @@ } #endif /* MULTIBUFFER */ -#if !defined(DISABLE_SPELLER) || !defined(DISABLE_OPERATINGDIR) +#if defined(ENABLE_NANORC) || !defined(DISABLE_SPELLER) || !defined(DISABLE_OPERATINGDIR) /* * When passed "[relative path]" or "[relative path][filename]" in * origpath, return "[full path]" or "[full path][filename]" on success, diff -ur nano-1.2.2/global.c nano-1.2.2-fixed/global.c --- nano-1.2.2/global.c 2003-08-05 21:15:15.000000000 -0600 +++ nano-1.2.2-fixed/global.c 2003-09-09 16:45:34.000000000 -0600 @@ -127,6 +127,7 @@ const colortype *colorstrings = NULL; syntaxtype *syntaxes = NULL; char *syntaxstr = NULL; +int display_syntax = 0; #endif #if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || (!defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)) diff -ur nano-1.2.2/nano.c nano-1.2.2-fixed/nano.c --- nano-1.2.2/nano.c 2003-08-05 21:15:15.000000000 -0600 +++ nano-1.2.2-fixed/nano.c 2003-09-09 16:49:48.000000000 -0600 @@ -657,6 +657,7 @@ print1opt("-V", "--version", _("Print version information and exit")); #ifdef ENABLE_COLOR print1opt(_("-Y [str]"), _("--syntax [str]"), _("Syntax definition to use")); + print1opt(_("-d"), _("--display-syntax"), _("Display syntax definitions")); #endif print1opt("-c", "--const", _("Constantly show cursor position")); #ifndef NANO_SMALL @@ -3030,6 +3031,7 @@ {"version", 0, 0, 'V'}, #ifdef ENABLE_COLOR {"syntax", 1, 0, 'Y'}, + {"display-syntax", 0, 0, 'd'}, #endif {"const", 0, 0, 'c'}, {"nofollow", 0, 0, 'l'}, @@ -3080,11 +3082,11 @@ #endif #ifdef HAVE_GETOPT_LONG - while ((optchr = getopt_long(argc, argv, "h?BDFHIKMNQ:RST:VY:abcefgijklmo:pr:s:tvwxz", + while ((optchr = getopt_long(argc, argv, "h?BDFHIKMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz", long_options, &option_index)) != -1) { #else while ((optchr = - getopt(argc, argv, "h?BDFHIKMNQ:RST:VY:abcefgijklmo:pr:s:tvwxz")) != -1) { + getopt(argc, argv, "h?BDFHIKMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz")) != -1) { #endif switch (optchr) { @@ -3169,6 +3171,9 @@ case 'Y': syntaxstr = mallocstrcpy(syntaxstr, optarg); break; + case 'd': + display_syntax = 1; + break; #endif case 'c': SET(CONSTUPDATE); diff -ur nano-1.2.2/nano.h nano-1.2.2-fixed/nano.h --- nano-1.2.2/nano.h 2003-08-03 20:51:12.000000000 -0600 +++ nano-1.2.2-fixed/nano.h 2003-09-10 03:12:52.000000000 -0600 @@ -180,24 +180,32 @@ #ifdef ENABLE_COLOR typedef struct colortype { + struct { + int insensitive:1; /* case-insensitive matches */ +// int or:1; /* only evaluate color if last match was unsuccessful */ +// int group:1; /* part of a multiple RE color directive */ + } flags; int fg; /* fg color */ int bg; /* bg color */ int bright; /* Is this color A_BOLD? */ int pairnum; /* Color pair number used for this fg/bg */ - regex_t start; /* Start (or all) of the regex string */ - regex_t *end; /* End of the regex string */ + char *start_regex; /* Start (or all) of the regex string */ + regex_t start; /* Compiled regex string */ + char *end_regex; /* End of the regex string */ + regex_t *end; /* Compiled regex string */ struct colortype *next; } colortype; typedef struct exttype { - regex_t val; /* The extensions that match this syntax. */ + char *ext_regex; /* The file extensions that match this syntax. */ struct exttype *next; } exttype; typedef struct syntaxtype { - char *desc; /* Name of this syntax type */ - exttype *extensions; /* List of extensions that this applies to */ - colortype *color; /* color struct for this syntax */ + int compiled; /* Set when color list has been compiled */ + char *desc; /* Name of this syntax */ + exttype *extensions; /* List of file extensions that this syntax applies to */ + colortype *colors; /* List of color expression used by this syntax */ struct syntaxtype *next; } syntaxtype; diff -ur nano-1.2.2/proto.h nano-1.2.2-fixed/proto.h --- nano-1.2.2/proto.h 2003-08-03 20:51:12.000000000 -0600 +++ nano-1.2.2-fixed/proto.h 2003-09-10 02:41:38.000000000 -0600 @@ -81,6 +81,7 @@ extern const colortype *colorstrings; extern syntaxtype *syntaxes; extern char *syntaxstr; +extern int display_syntax; #endif extern shortcut *shortcut_list; @@ -334,13 +335,15 @@ char *parse_next_word(char *ptr); char *parse_argument(char *ptr); #ifdef ENABLE_COLOR +void parse_include(char *ptr); int colortoint(const char *colorname, int *bright); char *parse_next_regex(char *ptr); -int nregcomp(regex_t *preg, const char *regex, int flags); -void parse_syntax(char *ptr); -void parse_colors(char *ptr); +int nregcomp(const char *regex, int flags); +int parse_syntax(char *ptr); +int parse_defaultsyntax(char *ptr); +void parse_colors(char *ptr, int insensitive); #endif /* ENABLE_COLOR */ -void parse_rcfile(FILE *rcstream); +void parse_rcfile(FILE *rcstream, int color_only); void do_rcfile(void); #endif /* ENABLE_NANORC */ diff -ur nano-1.2.2/rcfile.c nano-1.2.2-fixed/rcfile.c --- nano-1.2.2/rcfile.c 2003-08-05 21:15:15.000000000 -0600 +++ nano-1.2.2-fixed/rcfile.c 2003-09-10 03:13:15.000000000 -0600 @@ -240,48 +240,60 @@ return ptr; } -/* 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) +/* Compile the regular expression regex to preg. + Returns FALSE on success, TRUE if the expression is invalid. */ +int nregcomp(const char *regex, int flags) { - int rc = regcomp(preg, regex, REG_EXTENDED | flags); + regex_t preg; + int rc = regcomp(&preg, regex, REG_EXTENDED | flags); if (rc != 0) { - size_t len = regerror(rc, preg, NULL, 0); + size_t len = regerror(rc, &preg, NULL, 0); char *str = charalloc(len); - regerror(rc, preg, str, len); + regerror(rc, &preg, str, len); rcfile_error(_("Bad regex \"%s\": %s"), regex, str); free(str); } + regfree(&preg); return rc != 0; } -void parse_syntax(char *ptr) +int parse_syntax(char *ptr) { - syntaxtype *tmpsyntax = NULL; + syntaxtype *tmpsyntax = NULL, *prevsyntax = NULL; const char *fileregptr = NULL, *nameptr = NULL; exttype *endext = NULL; /* The end of the extensions list for this syntax. */ + char *name; while (*ptr == ' ') ptr++; - if (*ptr == '\n' || *ptr == '\0') - return; + if (*ptr == '\n' || *ptr == '\0') { + rcfile_error(_("Missing syntax name")); + return 0; + } if (*ptr != '"') { rcfile_error(_("regex strings must begin and end with a \" character\n")); - return; + return 0; } ptr++; nameptr = ptr; ptr = parse_next_regex(ptr); - if (ptr == NULL) { + if (ptr == NULL || strlen(nameptr) == 0) { rcfile_error(_("Missing syntax name")); - return; + return 0; + } + + for (name = (char *)nameptr; *name != '\0'; name++) { + if (*name == '*') { + rcfile_error(_("-- Syntax names can not contain '*' characters --")); + return 0; + } } if (syntaxes == NULL) { @@ -289,18 +301,24 @@ tmpsyntax = syntaxes; SET(COLOR_SYNTAX); } else { - for (tmpsyntax = syntaxes; tmpsyntax->next != NULL; - tmpsyntax = tmpsyntax->next) - ; - tmpsyntax->next = (syntaxtype *)nmalloc(sizeof(syntaxtype)); - tmpsyntax = tmpsyntax->next; + for (tmpsyntax = syntaxes; tmpsyntax != NULL; tmpsyntax = tmpsyntax->next) { + /* has syntax name already been defined? */ + if (!strcasecmp(nameptr, tmpsyntax->desc)) { + rcfile_error(_("-- syntax '%s' already defined --"), nameptr); + return 0; + } + prevsyntax = tmpsyntax; + } + + tmpsyntax = prevsyntax->next = (syntaxtype *)nmalloc(sizeof(syntaxtype)); #ifdef DEBUG fprintf(stderr, "Adding new syntax after 1st\n"); #endif } + tmpsyntax->compiled = 0; tmpsyntax->desc = mallocstrcpy(NULL, nameptr); - tmpsyntax->color = NULL; tmpsyntax->extensions = NULL; + tmpsyntax->colors = NULL; tmpsyntax->next = NULL; #ifdef DEBUG fprintf(stderr, "Starting a new syntax type\n"); @@ -316,16 +334,18 @@ ptr++; if (*ptr == '\n' || *ptr == '\0') - return; + break; ptr++; fileregptr = ptr; ptr = parse_next_regex(ptr); newext = (exttype *)nmalloc(sizeof(exttype)); - if (nregcomp(&newext->val, fileregptr, REG_NOSUB)) + newext->ext_regex = mallocstrcpy(NULL, fileregptr); + if (nregcomp(fileregptr, REG_NOSUB)) { + free(newext->ext_regex); free(newext); - else { + } else { if (endext == NULL) tmpsyntax->extensions = newext; else @@ -334,10 +354,105 @@ endext->next = NULL; } } + if (tmpsyntax->extensions == NULL) { + free(tmpsyntax->desc); + free(tmpsyntax); + if (prevsyntax != NULL) + prevsyntax->next = NULL; + + rcfile_error(_("-- Missing syntax extensions for '%s' --"), nameptr); + return 0; + } + return 1; +} + +/* Create a default syntax */ +int parse_defaultsyntax(char *ptr) +{ + syntaxtype *tmpsyntax; + + /* warn if the user gives us parameters */ + for (; *ptr != '\n' && *ptr != '\0'; ptr++) + if (*ptr == '\n' || *ptr == '\0') + rcfile_error(_("-- The default-syntax directive should not have parameters --")); + + if (syntaxes == NULL) { + syntaxes = (syntaxtype *)nmalloc(sizeof(syntaxtype)); + tmpsyntax = syntaxes; + SET(COLOR_SYNTAX); + } else { + for (tmpsyntax = syntaxes; tmpsyntax->next != NULL; tmpsyntax = tmpsyntax->next); + + tmpsyntax->next = (syntaxtype *)nmalloc(sizeof(syntaxtype)); + tmpsyntax = tmpsyntax->next; +#ifdef DEBUG + fprintf(stderr, "Adding default syntax after 1st\n"); +#endif + } + tmpsyntax->compiled = 0; + tmpsyntax->desc = NULL; + tmpsyntax->extensions = NULL; + tmpsyntax->colors = NULL; + tmpsyntax->next = NULL; +#ifdef DEBUG + fprintf(stderr, "Starting a default syntax type\n"); +#endif + + return 1; +} + +/* Read and parse additional syntax files. */ +void parse_include(char *ptr) +{ + FILE *rc; + char *option, *full_option, *err_filename = NULL, *err_message; + char *old_nanorc = nanorc; + int old_lineno = lineno; + + option = ptr; + if (*option == '"') + option++; + ptr = parse_argument(ptr); + + /* Get the specified file's full path. There are three ways in + * which this can go wrong: get_full_path() fails, get_full_path() + * returns a directory, or get_full_path() succeeds and returns a + * filename but fopen() fails. Set the filename and error message + * accordingly in each of these cases. */ + + full_option = get_full_path(option); + + if (full_option == NULL) { + err_filename = option; + err_message = strerror(errno); + } else if (full_option[strlen(full_option) - 1] == '/') { + err_filename = full_option; + err_message = _("Not a file\n"); + } else if ((rc = fopen(full_option, "r")) == NULL) { + err_filename = full_option; + err_message = strerror(errno); + } + if (err_filename != NULL) + rcfile_error(_("Unable to read file %s, %s"), err_filename, err_message); + else { + /* Use the name and line number position of the file while + * parsing it, so we can know where any errors in it are. */ + nanorc = full_option; + lineno = 0; + + parse_rcfile(rc, 1); + fclose(rc); + free(full_option); + + /* We're done with the file; set the name and line number + * position back to those of the old file. */ + nanorc = old_nanorc; + lineno = old_lineno; + } } /* Parse the color stuff into the colorstrings array */ -void parse_colors(char *ptr) +void parse_colors(char *ptr, int insensitive) { int fg, bg, bright = 0; int expectend = 0; /* Do we expect an end= line? */ @@ -365,11 +480,6 @@ if (fg == -1) return; - if (syntaxes == NULL) { - rcfile_error(_("Cannot add a color directive without a syntax line")); - return; - } - for (tmpsyntax = syntaxes; tmpsyntax->next != NULL; tmpsyntax = tmpsyntax->next) ; @@ -402,26 +512,36 @@ ptr++; newcolor = (colortype *)nmalloc(sizeof(colortype)); + fgstr = ptr; ptr = parse_next_regex(ptr); - if (nregcomp(&newcolor->start, fgstr, 0)) { + + newcolor->start_regex = mallocstrcpy(NULL, fgstr); + if (nregcomp(fgstr, insensitive ? REG_ICASE : 0)) { + free(newcolor->start_regex); free(newcolor); cancelled = 1; } else { + newcolor->flags.insensitive = insensitive; + +// set newcolor->flags.or +// set newcolor->flags.group + newcolor->fg = fg; newcolor->bg = bg; newcolor->bright = bright; newcolor->next = NULL; + newcolor->end_regex = NULL; newcolor->end = NULL; - if (tmpsyntax->color == NULL) { - tmpsyntax->color = newcolor; + if (tmpsyntax->colors == NULL) { + tmpsyntax->colors = newcolor; #ifdef DEBUG fprintf(stderr, "Starting a new colorstring for fg %d bg %d\n", fg, bg); #endif } else { - for (tmpcolor = tmpsyntax->color; tmpcolor->next != NULL; + for (tmpcolor = tmpsyntax->colors; tmpcolor->next != NULL; tmpcolor = tmpcolor->next) ; #ifdef DEBUG @@ -433,16 +553,14 @@ if (expectend) { if (ptr == NULL || strncasecmp(ptr, "end=", 4)) { - rcfile_error(_ - ("\"start=\" requires a corresponding \"end=\"")); + rcfile_error(_("\"start=\" requires a corresponding \"end=\"")); return; } ptr += 4; if (*ptr != '"') { - rcfile_error(_ - ("regex strings must begin and end with a \" character\n")); + rcfile_error(_("regex strings must begin and end with a \" character\n")); continue; } ptr++; @@ -454,10 +572,10 @@ * 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; + newcolor->end_regex = mallocstrcpy(NULL, fgstr); + if (nregcomp(fgstr, insensitive ? REG_ICASE : 0)) { + free(newcolor->end_regex); + newcolor->end_regex = NULL; } } } @@ -466,10 +584,13 @@ #endif /* ENABLE_COLOR */ /* Parse the RC file, once it has been opened successfully */ -void parse_rcfile(FILE *rcstream) +void parse_rcfile(FILE *rcstream, int color_only) { char *buf, *ptr, *keyword, *option; int set = 0, i, j; +#ifdef ENABLE_COLOR + int syntax_ok = 1, defaultsyntax = 0, syntax = color_only; +#endif buf = charalloc(1024); while (fgets(buf, 1023, rcstream) != 0) { @@ -495,17 +616,57 @@ continue; /* Else try to parse the keyword */ - if (!strcasecmp(keyword, "set")) - set = 1; - else if (!strcasecmp(keyword, "unset")) - set = -1; + if (!strcasecmp(keyword, "set")) { #ifdef ENABLE_COLOR - else if (!strcasecmp(keyword, "syntax")) - parse_syntax(ptr); - else if (!strcasecmp(keyword, "color")) - parse_colors(ptr); + if (color_only) + rcfile_error(_("-- Cannot add a set directive inside included files --")); + else +#endif + set = 1; + } else if (!strcasecmp(keyword, "unset")) { +#ifdef ENABLE_COLOR + if (color_only) + rcfile_error(_("-- Cannot add an unset directive inside included files --")); + else +#endif + set = -1; +#ifdef ENABLE_COLOR + } else if (!strcasecmp(keyword, "syntax")) { + if (color_only) + rcfile_error(_("-- Cannot add a syntax directive inside included files --")); + else { + syntax_ok = parse_syntax(ptr); + syntax = 1; + } + } else if (!strcasecmp(keyword, "default-syntax")) { + if (color_only) + rcfile_error(_("-- Cannot add a default-syntax directive inside included files --")); + else if (defaultsyntax){ + rcfile_error(_("-- A default syntax has already been defined --")); + syntax_ok = 0; + } else { + syntax_ok = parse_defaultsyntax(ptr); + defaultsyntax = syntax = 1; + } + } else if (!strcasecmp(keyword, "include")) { + if (color_only) + rcfile_error(_("-- Cannot add an include directive inside included files --")); + else if (!syntax) + rcfile_error(_("-- Cannot add an include directive without a syntax line --")); + else if (syntax_ok) + parse_include(ptr); + } else if (!strcasecmp(keyword, "color")) { + if (!syntax) + rcfile_error(_("Cannot add a color directive without a syntax line")); + else if (syntax_ok) + parse_colors(ptr, 0); + } else if (!strcasecmp(keyword, "icolor")) { + if (!syntax) + rcfile_error(_("-- Cannot add an icolor directive without a syntax line --")); + else if (syntax_ok) + parse_colors(ptr, 1); #endif /* ENABLE_COLOR */ - else { + } else { rcfile_msg(_("command %s not understood"), keyword); continue; } @@ -631,7 +792,7 @@ /* Try to open system nanorc */ if ((rcstream = fopen(nanorc, "r")) != NULL) { /* Parse it! */ - parse_rcfile(rcstream); + parse_rcfile(rcstream, 0); fclose(rcstream); } #endif @@ -672,7 +833,7 @@ SET(NO_RCFILE); } } else { - parse_rcfile(rcstream); + parse_rcfile(rcstream, 0); fclose(rcstream); } } @@ -681,6 +842,29 @@ free(nanorc); #ifdef ENABLE_COLOR set_colorpairs(); + + if (display_syntax) { + const syntaxtype *tmpsyntax; + + for(tmpsyntax = syntaxes; tmpsyntax != NULL; tmpsyntax = tmpsyntax->next) { + const colortype *tmpcolor; + + for(tmpcolor = tmpsyntax->colors; tmpcolor != NULL; tmpcolor = tmpcolor->next) { + if (tmpcolor->end_regex == NULL) + printf("%s: color \"%s\"\n", tmpsyntax->desc == NULL ? "*" : tmpsyntax->desc, + tmpcolor->start_regex); + else + printf("%s: color start=\"%s\" end=\"%s\"\n", + tmpsyntax->desc == NULL ? "*" : tmpsyntax->desc, + tmpcolor->start_regex, tmpcolor->end_regex); + + // TODO: display human readable color names + + } + printf("\n"); + } + exit(1); + } #endif }