diff -ur nano-1.3.0/src/color.c nano-1.3.0-p2/src/color.c --- nano-1.3.0/src/color.c 2003-09-06 18:44:12.000000000 -0600 +++ nano-1.3.0-p2/src/color.c 2003-11-08 23:44:09.000000000 -0700 @@ -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,31 +101,117 @@ /* 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) { + if (!strcasecmp("none", syntaxstr)) + return; + + for (tmpsyntax = syntaxes; tmpsyntax != NULL; tmpsyntax = tmpsyntax->next) { + if(tmpsyntax->desc == NULL) { + if (!strcasecmp("default", syntaxstr)) { + colorstrings = tmpsyntax->colors; + break; + } + } else 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) { + regex_t preg; + + /* skip default syntax */ + if (tmpsyntax->desc == NULL) + continue; + + /* 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) { + if (c->flags.defaultcolor) + continue; + + regcomp(&c->start, c->start_regex, + (c->flags.insensitive ? REG_ICASE : 0) | REG_EXTENDED); + 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); + } } + + tmpsyntax->compiled = 1; } + do_colorinit(); } +int regexec_wrapper(const colortype *color, const regex_t *preg, const char *string, size_t nmatch, + regmatch_t pmatch[], int eflags) { + /* Each regex_t will be freed and recompiled every 100 calls */ + if (color->counter > 100) { + /* calls kB (maximum regexec leakage) + * ----------- + * 200 56 + * 150 40 + * 125 28 + * 100 20 + * 50 20 + */ + + regfree((regex_t *)&color->start); + regcomp((regex_t *)&color->start, color->start_regex, + (color->flags.insensitive ? REG_ICASE : 0) | REG_EXTENDED); + if (color->end_regex != NULL) { + regfree(color->end); + regcomp(color->end, color->end_regex, + (color->flags.insensitive ? REG_ICASE : 0) | REG_EXTENDED); + } + ((colortype *)color)->counter = 0; + } + + ((colortype *)color)->counter++; + return regexec(preg, string, nmatch, pmatch, eflags); +} + #endif /* ENABLE_COLOR */ diff -ur nano-1.3.0/src/files.c nano-1.3.0-p2/src/files.c --- nano-1.3.0/src/files.c 2003-10-23 18:14:41.000000000 -0600 +++ nano-1.3.0-p2/src/files.c 2003-11-08 23:05:44.000000000 -0700 @@ -1017,7 +1017,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.3.0/src/nano.c nano-1.3.0-p2/src/nano.c --- nano-1.3.0/src/nano.c 2003-10-23 18:14:41.000000000 -0600 +++ nano-1.3.0-p2/src/nano.c 2003-11-08 23:05:44.000000000 -0700 @@ -643,6 +643,9 @@ print1opt("-M", "--mac", _("Write file in Mac format")); print1opt("-N", "--noconvert", _("Don't convert files from DOS/Mac format")); #endif +#ifdef ENABLE_COLOR + print1opt(_("-P"), _("--displaysyntax"), _("Display syntax definitions")); +#endif #ifndef DISABLE_JUSTIFY print1opt(_("-Q [str]"), _("--quotestr=[str]"), _("Quoting string, default \"> \"")); #endif @@ -3051,6 +3054,9 @@ #endif {"ignorercfiles", 0, 0, 'I'}, #endif +#ifdef ENABLE_COLOR + {"displaysyntax", 0, 0, 'P'}, +#endif #ifndef DISABLE_JUSTIFY {"quotestr", 1, 0, 'Q'}, #endif @@ -3112,11 +3118,11 @@ #endif #ifdef HAVE_GETOPT_LONG - while ((optchr = getopt_long(argc, argv, "h?BDFHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz", + while ((optchr = getopt_long(argc, argv, "h?BDFHIMNPQ:RST:VY:abcdefgijklmo:pr:s:tvwxz", long_options, &option_index)) != -1) { #else while ((optchr = - getopt(argc, argv, "h?BDFHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz")) != -1) { + getopt(argc, argv, "h?BDFHIMNPQ:RST:VY:abcdefgijklmo:pr:s:tvwxz")) != -1) { #endif switch (optchr) { @@ -3160,6 +3166,11 @@ SET(NO_CONVERT); break; #endif +#ifdef ENABLE_COLOR + case 'P': + SET(DISPLAY_SYNTAX); + break; +#endif #ifndef DISABLE_JUSTIFY case 'Q': quotestr = mallocstrcpy(quotestr, optarg); diff -ur nano-1.3.0/src/nano.h nano-1.3.0-p2/src/nano.h --- nano-1.3.0/src/nano.h 2003-10-23 18:14:41.000000000 -0600 +++ nano-1.3.0-p2/src/nano.h 2003-11-08 23:57:05.000000000 -0700 @@ -200,24 +200,32 @@ #ifdef ENABLE_COLOR typedef struct colortype { + struct { + int insensitive:1; /* case-insensitive matches */ + int defaultcolor:1; /* default color for syntax - no regexps */ + } 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 */ + int counter; /* Number of times regexec() has been called */ 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; @@ -272,6 +280,7 @@ #define HISTORY_CHANGED (1<<28) #define HISTORYLOG (1<<29) #define JUSTIFY_MODE (1<<30) +#define DISPLAY_SYNTAX (1<<31) /* Control key sequences, changing these would be very very bad */ diff -ur nano-1.3.0/src/proto.h nano-1.3.0-p2/src/proto.h --- nano-1.3.0/src/proto.h 2003-10-23 18:14:41.000000000 -0600 +++ nano-1.3.0-p2/src/proto.h 2003-11-08 23:05:44.000000000 -0700 @@ -135,6 +135,8 @@ void set_colorpairs(void); void do_colorinit(void); void update_color(void); +int regexec_wrapper(const colortype *color, const regex_t *preg, const char *string, size_t nmatch, + regmatch_t pmatch[], int eflags); #endif /* ENABLE_COLOR */ /* Public functions in cut.c */ @@ -340,13 +342,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 ctflags); #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.3.0/src/rcfile.c nano-1.3.0-p2/src/rcfile.c --- nano-1.3.0/src/rcfile.c 2003-10-23 18:14:42.000000000 -0600 +++ nano-1.3.0-p2/src/rcfile.c 2003-11-09 00:50:06.000000000 -0700 @@ -242,48 +242,85 @@ 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) +/* Free a syntax -- needed so users can override syntaxes from /etc/nanorc */ +void free_syntax(syntaxtype *prevsyntax, syntaxtype *syntax) { - syntaxtype *tmpsyntax = NULL; + exttype *ext = syntax->extensions; + colortype *color = syntax->colors; + + if (prevsyntax) + prevsyntax->next = syntax->next; + else syntaxes = syntax->next; + + while (ext != NULL) { + exttype *nextext = ext->next; + if (ext->ext_regex) free(ext->ext_regex); + free(ext); + ext = nextext; + } + while (color != NULL) { + colortype *nextcolor = color->next; + if (color->start_regex) free(color->start_regex); + if (color->end_regex) free(color->end_regex); + free(color); + color = nextcolor; + } + free(syntax); +} + +/* Create a normal syntax */ +int parse_syntax(char *ptr) +{ + syntaxtype *tmpsyntax, *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; + } + + if (!strcasecmp("default", nameptr) || !strcasecmp("none", nameptr)) { + rcfile_error(_("-- Syntax name '%s' is reserved --"), nameptr); + return 0; } if (syntaxes == NULL) { @@ -291,18 +328,27 @@ tmpsyntax = syntaxes; SET(COLOR_SYNTAX); } else { - for (tmpsyntax = syntaxes; tmpsyntax->next != NULL; - tmpsyntax = tmpsyntax->next) - ; - tmpsyntax->next = (syntaxtype *)nmalloc(sizeof(syntaxtype)); - tmpsyntax = tmpsyntax->next; + tmpsyntax = syntaxes; + while (tmpsyntax != NULL) { + syntaxtype *next = tmpsyntax->next; + + /* remove existing syntaxes with same name */ + if (tmpsyntax->desc != NULL && !strcasecmp(nameptr, tmpsyntax->desc)) + free_syntax(prevsyntax, tmpsyntax); + else prevsyntax = tmpsyntax; + + tmpsyntax = next; + } + + 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"); @@ -318,16 +364,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 @@ -336,16 +384,113 @@ endext->next = NULL; } } + return 1; +} + +/* Create a default syntax */ +int parse_defaultsyntax(char *ptr) +{ + syntaxtype *tmpsyntax, *prevsyntax = NULL; + + /* 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 { + tmpsyntax = syntaxes; + while (tmpsyntax != NULL) { + syntaxtype *next = tmpsyntax->next; + + /* remove existing default syntaxes */ + if (tmpsyntax->desc == NULL) + free_syntax(prevsyntax, tmpsyntax); + else prevsyntax = tmpsyntax; + + tmpsyntax = next; + } + + tmpsyntax = prevsyntax->next = (syntaxtype *)nmalloc(sizeof(syntaxtype)); +#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; + } } +#define CTFLAG_INSENSITIVE 1 +#define CTFLAG_DEFAULTCOLOR 2 + /* Parse the color stuff into the colorstrings array */ -void parse_colors(char *ptr) +void parse_colors(char *ptr, int ctflags) { int fg, bg, bright = 0; int expectend = 0; /* Do we expect an end= line? */ char *fgstr; - colortype *tmpcolor = NULL; - syntaxtype *tmpsyntax = NULL; + syntaxtype *tmpsyntax; fgstr = ptr; ptr = parse_next_word(ptr); @@ -373,11 +518,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) ; @@ -385,7 +525,42 @@ /* Now the fun part, start adding regexps to individual strings in the colorstrings array, woo! */ - while (*ptr != '\0') { + if (ctflags & CTFLAG_DEFAULTCOLOR) { + colortype *newcolor; + /* The new color structure. */ + + while (*ptr != '\0' && *ptr == ' ') + ptr++; + if (*ptr != '\0') { + rcfile_error(_("-- The default-color directive should only have a single color parameter --")); + return; + } + + newcolor = (colortype *)nmalloc(sizeof(colortype)); + + /* insensitive flag is ignored */ + newcolor->flags.defaultcolor = 1; + + newcolor->fg = fg; + newcolor->bg = bg; + newcolor->bright = bright; + newcolor->next = NULL; + newcolor->start_regex = NULL; + newcolor->end_regex = NULL; + newcolor->end = NULL; + newcolor->counter = 0; + + if (tmpsyntax->colors == NULL) { + tmpsyntax->colors = newcolor; +#ifdef DEBUG + fprintf(stderr, "Setting a default color for fg %d bg %d\n", fg, bg); +#endif + } else { + free(newcolor); + rcfile_error(_("-- Default color must be set before any other colors --")); + return; + } + } else while (*ptr != '\0') { colortype *newcolor; /* The new color structure. */ int cancelled = 0; @@ -410,26 +585,37 @@ 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, ctflags & CTFLAG_INSENSITIVE ? REG_ICASE : 0)) { + free(newcolor->start_regex); free(newcolor); cancelled = 1; } else { + newcolor->flags.insensitive = ctflags & CTFLAG_INSENSITIVE; + newcolor->flags.defaultcolor = 0; + newcolor->fg = fg; newcolor->bg = bg; newcolor->bright = bright; newcolor->next = NULL; + newcolor->end_regex = NULL; newcolor->end = NULL; + newcolor->counter = 0; - 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; + colortype *tmpcolor = NULL; + + for (tmpcolor = tmpsyntax->colors; tmpcolor->next != NULL; tmpcolor = tmpcolor->next) ; #ifdef DEBUG @@ -441,16 +627,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++; @@ -462,10 +646,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, ctflags & CTFLAG_INSENSITIVE ? REG_ICASE : 0)) { + free(newcolor->end_regex); + newcolor->end_regex = NULL; } } } @@ -474,10 +658,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, syntax = color_only; +#endif buf = charalloc(1024); while (fgets(buf, 1023, rcstream) != 0) { @@ -503,17 +690,59 @@ 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 + if (color_only) + rcfile_error(_("-- Cannot use a set directive inside included files --")); + else +#endif + set = 1; + } else if (!strcasecmp(keyword, "unset")) { +#ifdef ENABLE_COLOR + if (color_only) + rcfile_error(_("-- Cannot use an unset directive inside included files --")); + else +#endif + set = -1; #ifdef ENABLE_COLOR - else if (!strcasecmp(keyword, "syntax")) - parse_syntax(ptr); - else if (!strcasecmp(keyword, "color")) - parse_colors(ptr); + } else if (!strcasecmp(keyword, "syntax")) { + if (color_only) { + rcfile_error(_("-- Cannot use 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 use a default-syntax directive inside included files --")); + } else { + syntax_ok = parse_defaultsyntax(ptr); + syntax = 1; + } + } else if (!strcasecmp(keyword, "include")) { + if (color_only) + rcfile_error(_("-- Cannot use an include directive inside included files --")); + else if (!syntax) + rcfile_error(_("-- Cannot use an include directive without a syntax line --")); + else if (syntax_ok) + parse_include(ptr); + } else if (!strcasecmp(keyword, "color")) { + if (!syntax) + rcfile_error(_("-- Cannot use 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 use an icolor directive without a syntax line --")); + else if (syntax_ok) + parse_colors(ptr, CTFLAG_INSENSITIVE); + } else if (!strcasecmp(keyword, "default-color")) { + if (!syntax) + rcfile_error(_("-- Cannot use a default-color directive without a syntax line --")); + else if (syntax_ok) + parse_colors(ptr, CTFLAG_DEFAULTCOLOR); #endif /* ENABLE_COLOR */ - else { + } else { rcfile_msg(_("Command %s not understood"), keyword); continue; } @@ -624,6 +853,33 @@ return; } +void display_syntax_colors(int level, char *desc, const colortype *color) +{ + for (; color != NULL; color = color->next) { + char *colorname; + int n; + + printf("%s: ", desc == NULL ? "default" : desc); + + for (n = 0; n < level; n++) + printf(" "); + + /* TODO: display human readable color names */ + colorname = "---"; + + if (color->flags.defaultcolor) + printf("default-color %s\n", colorname); + else if (color->end_regex == NULL) + printf("%s %s \"%s\"\n", + color->flags.insensitive ? "icolor" : "color", + colorname, color->start_regex); + else + printf("%s %s start=\"%s\" end=\"%s\"\n", + color->flags.insensitive ? "icolor" : "color", + colorname, color->start_regex, color->end_regex); + } +} + /* The main rc file function, tries to open the rc file */ void do_rcfile(void) { @@ -639,7 +895,7 @@ /* Try to open system nanorc */ if ((rcstream = fopen(nanorc, "r")) != NULL) { /* Parse it! */ - parse_rcfile(rcstream); + parse_rcfile(rcstream, 0); fclose(rcstream); } #endif @@ -680,7 +936,7 @@ SET(NO_RCFILE); } } else { - parse_rcfile(rcstream); + parse_rcfile(rcstream, 0); fclose(rcstream); } } @@ -689,6 +945,24 @@ free(nanorc); #ifdef ENABLE_COLOR set_colorpairs(); + + if (ISSET(DISPLAY_SYNTAX)) { + const syntaxtype *tmpsyntax; + + for(tmpsyntax = syntaxes; tmpsyntax != NULL; tmpsyntax = tmpsyntax->next) { + const exttype *ext; + + for (ext = tmpsyntax->extensions; ext != NULL; ext = ext->next) + printf("%s: extension \"%s\"\n", + tmpsyntax->desc == NULL ? "default" : tmpsyntax->desc, + ext->ext_regex); + + display_syntax_colors(0, tmpsyntax->desc, tmpsyntax->colors); + + printf("\n"); + } + exit(1); + } #endif } diff -ur nano-1.3.0/src/winio.c nano-1.3.0-p2/src/winio.c --- nano-1.3.0/src/winio.c 2003-11-03 18:48:24.000000000 -0700 +++ nano-1.3.0-p2/src/winio.c 2003-11-09 01:21:03.000000000 -0700 @@ -748,7 +748,7 @@ xend = strlen(history); /* if there is no newer search, we're here */ - + /* if currentbuf isn't NULL and use_cb isn't 2, it means that we're scrolling down at the bottom of the search history and we need to make the string in currentbuf @@ -1034,52 +1034,70 @@ assert(fileptr != NULL && converted != NULL); assert(strlen(converted) <= COLS); - /* Just paint the string in any case (we'll add color or reverse on - * just the text that needs it). */ - mvwaddstr(edit, yval, 0, converted); - #ifdef ENABLE_COLOR if (colorstrings != NULL && ISSET(COLOR_SYNTAX)) { const colortype *tmpcolor = colorstrings; + if (tmpcolor->flags.defaultcolor) { + if (tmpcolor->bright) + wattron(edit, A_BOLD); + wattron(edit, COLOR_PAIR(tmpcolor->pairnum)); + + /* Display line - color will be added to just the text that needs it */ + mvwaddstr(edit, yval, 0, converted); + + if (tmpcolor->bright) + wattroff(edit, A_BOLD); + wattroff(edit, COLOR_PAIR(tmpcolor->pairnum)); + + tmpcolor = tmpcolor->next; + } else { + /* Display line - color will be added to just the text that needs it */ + mvwaddstr(edit, yval, 0, converted); + } + for (; tmpcolor != NULL; tmpcolor = tmpcolor->next) { int x_start; /* Starting column for mvwaddnstr. Zero-based. */ int paintlen; - /* Number of chars to paint on this line. There are COLS - * characters on a whole line. */ - regmatch_t startmatch; /* match position for start_regexp */ - regmatch_t endmatch; /* match position for end_regexp */ + /* Number of chars to paint on this line. + * There are COLS characters on a whole line. */ + regmatch_t startmatch, endmatch; + /* match position for start_regexp and end_regexp */ if (tmpcolor->bright) wattron(edit, A_BOLD); wattron(edit, COLOR_PAIR(tmpcolor->pairnum)); + /* Two notes about regexec(). Return value 0 means there is * a match. Also, rm_eo is the first non-matching character * after the match. */ /* First case, tmpcolor is a single-line expression. */ if (tmpcolor->end == NULL) { - size_t k = 0; + size_t k; /* We increment k by rm_eo, to move past the end of the * last match. Even though two matches may overlap, we * want to ignore them, so that we can highlight * C-strings correctly. */ - while (k < endpos) { + for (k = 0; k < endpos; k = startmatch.rm_eo) { /* Note the fifth parameter to regexec(). It says * not to match the beginning-of-line character * 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, + if (regexec_wrapper(tmpcolor, &tmpcolor->start, &fileptr->data[k], 1, &startmatch, k == 0 ? 0 : REG_NOTBOL) == REG_NOMATCH) break; + /* 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")); + /* Abort to prevent problems with this bad regular expression */ + statusbar(_("Refusing zero length \"%s\" regex match"), tmpcolor->start_regex); + break; } else if (startmatch.rm_so < endpos && startmatch.rm_eo > startpos) { if (startmatch.rm_so <= startpos) @@ -1092,15 +1110,15 @@ if (paintlen > COLS - x_start) paintlen = COLS - x_start; - assert(0 <= x_start && 0 < paintlen && - x_start + paintlen <= COLS); - mvwaddnstr(edit, yval, x_start, - converted + x_start, paintlen); + /* assert(0 <= x_start && 0 < paintlen && x_start + paintlen <= COLS); + * The above IF statement guarantees part of this test */ + assert(0 <= x_start && 0 < paintlen); + + mvwaddnstr(edit, yval, x_start, converted + x_start, paintlen); } - k = startmatch.rm_eo; } } else { - /* This is a multi-line regexp. There are two steps. + /* This is a multi-line regexp. There are two steps. * First, we have to see if the beginning of the line is * colored by a start on an earlier line, and an end on * this line or later. @@ -1121,11 +1139,11 @@ * lines after fileptr? */ while (start_line != NULL && - regexec(&tmpcolor->start, start_line->data, 1, + regexec_wrapper(tmpcolor, &tmpcolor->start, start_line->data, 1, &startmatch, 0) == REG_NOMATCH) { /* If there is an end on this line, there is no need * to look for starts on earlier lines. */ - if (regexec(tmpcolor->end, start_line->data, 0, NULL, 0) + if (regexec_wrapper(tmpcolor, tmpcolor->end, start_line->data, 0, NULL, 0) == 0) goto step_two; start_line = start_line->prev; @@ -1141,14 +1159,14 @@ while (1) { start_col += startmatch.rm_so; startmatch.rm_eo -= startmatch.rm_so; - if (regexec(tmpcolor->end, + if (regexec_wrapper(tmpcolor, tmpcolor->end, start_line->data + start_col + startmatch.rm_eo, 0, NULL, start_col + startmatch.rm_eo == 0 ? 0 : REG_NOTBOL) == REG_NOMATCH) /* No end found after this start. */ break; start_col++; - if (regexec(&tmpcolor->start, + if (regexec_wrapper(tmpcolor, &tmpcolor->start, start_line->data + start_col, 1, &startmatch, REG_NOTBOL) == REG_NOMATCH) /* No later start on this line. */ @@ -1163,7 +1181,7 @@ * starts. */ end_line = fileptr; while (end_line != NULL && - regexec(tmpcolor->end, end_line->data, 1, &endmatch, 0)) + regexec_wrapper(tmpcolor, tmpcolor->end, end_line->data, 1, &endmatch, 0)) end_line = end_line->next; /* No end found, or it is too early. */ @@ -1177,7 +1195,10 @@ if (paintlen > COLS) paintlen = COLS; - assert(0 < paintlen && paintlen <= COLS); + /* assert(0 < paintlen && paintlen <= COLS); + * The above IF statement guarantees part of this test */ + assert(0 < paintlen); + mvwaddnstr(edit, yval, 0, converted, paintlen); /* We have already painted the whole line. */ @@ -1187,7 +1208,7 @@ step_two: /* Second step, we look for starts on this line. */ start_col = 0; while (start_col < endpos) { - if (regexec(&tmpcolor->start, fileptr->data + start_col, 1, + if (regexec_wrapper(tmpcolor, &tmpcolor->start, fileptr->data + start_col, 1, &startmatch, start_col == 0 ? 0 : REG_NOTBOL) == REG_NOMATCH || start_col + startmatch.rm_so >= endpos) @@ -1203,7 +1224,7 @@ else x_start = strnlenpt(fileptr->data, startmatch.rm_so) - start; - if (regexec(tmpcolor->end, fileptr->data + startmatch.rm_eo, + if (regexec_wrapper(tmpcolor, tmpcolor->end, fileptr->data + startmatch.rm_eo, 1, &endmatch, startmatch.rm_eo == 0 ? 0 : REG_NOTBOL) == 0) { /* Translate the end match to be relative to the @@ -1220,10 +1241,11 @@ if (x_start + paintlen > COLS) paintlen = COLS - x_start; - assert(0 <= x_start && 0 < paintlen && - x_start + paintlen <= COLS); - mvwaddnstr(edit, yval, x_start, - converted + x_start, paintlen); + /* assert(0 <= x_start && 0 < paintlen && x_start + paintlen <= COLS); + * The above IF statement guarantees part of this test */ + assert(0 <= x_start && 0 < paintlen); + + mvwaddnstr(edit, yval, x_start, converted + x_start, paintlen); } } else if (!searched_later_lines) { searched_later_lines = 1; @@ -1231,7 +1253,7 @@ * yet looked for one on later lines. */ end_line = fileptr->next; while (end_line != NULL && - regexec(tmpcolor->end, end_line->data, 0, + regexec_wrapper(tmpcolor, tmpcolor->end, end_line->data, 0, NULL, 0) == REG_NOMATCH) end_line = end_line->next; if (end_line != NULL) { @@ -1249,10 +1271,18 @@ } /* if (tmp_color->end != NULL) */ skip_step_two: - wattroff(edit, A_BOLD); + + if (tmpcolor->bright) + wattroff(edit, A_BOLD); wattroff(edit, COLOR_PAIR(tmpcolor->pairnum)); } /* for tmpcolor in colorstrings */ + } else { + /* Display line - reverse will be added to just the text that needs it */ + mvwaddstr(edit, yval, 0, converted); } +#else + /* Display line - reverse will be added to just the text that needs it */ + mvwaddstr(edit, yval, 0, converted); #endif /* ENABLE_COLOR */ #ifndef NANO_SMALL @@ -1310,7 +1340,9 @@ x_start = 0; } - assert(x_start >= 0 && x_start <= strlen(converted)); + /* assert(x_start >= 0 && x_start <= strlen(converted)); + * The above IF statement guarantees part of this test */ + assert(x_start <= strlen(converted)); wattron(edit, A_REVERSE); mvwaddnstr(edit, yval, x_start, converted + x_start, paintlen);