Only in nano-1.3.0/: nano.spec diff -ur nano-1.3.0/src/color.c nano-1.3.0-p0/src/color.c --- nano-1.3.0/src/color.c 2003-09-06 18:44:12.000000000 -0600 +++ nano-1.3.0-p0/src/color.c 2003-10-30 19:27:52.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,30 +101,82 @@ /* 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(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) { + 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.3.0/src/files.c nano-1.3.0-p0/src/files.c --- nano-1.3.0/src/files.c 2003-10-23 18:14:41.000000000 -0600 +++ nano-1.3.0-p0/src/files.c 2003-10-30 03:22: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-p0/src/nano.c --- nano-1.3.0/src/nano.c 2003-10-23 18:14:41.000000000 -0600 +++ nano-1.3.0-p0/src/nano.c 2003-10-30 03:22: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-p0/src/nano.h --- nano-1.3.0/src/nano.h 2003-10-23 18:14:41.000000000 -0600 +++ nano-1.3.0-p0/src/nano.h 2003-10-30 15:22:33.000000000 -0700 @@ -200,24 +200,30 @@ #ifdef ENABLE_COLOR typedef struct colortype { + struct { + int insensitive:1; /* case-insensitive matches */ + } 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; @@ -272,6 +278,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-p0/src/proto.h --- nano-1.3.0/src/proto.h 2003-10-23 18:14:41.000000000 -0600 +++ nano-1.3.0-p0/src/proto.h 2003-10-30 15:25:40.000000000 -0700 @@ -340,13 +340,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-p0/src/rcfile.c --- nano-1.3.0/src/rcfile.c 2003-10-23 18:14:42.000000000 -0600 +++ nano-1.3.0-p0/src/rcfile.c 2003-10-30 19:33:38.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)) { + rcfile_error(_("-- Syntax name '%s' is reserved for the default syntax --"), 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,10 +384,107 @@ 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 + /* 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? */ @@ -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) ; @@ -410,26 +550,33 @@ 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->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 @@ -441,16 +588,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 +607,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 +619,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 +651,54 @@ 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 add a set directive inside included files --")); + else +#endif + set = 1; + } else if (!strcasecmp(keyword, "unset")) { #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 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 { + syntax_ok = parse_defaultsyntax(ptr); + 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, CTFLAG_INSENSITIVE); #endif /* ENABLE_COLOR */ - else { + } else { rcfile_msg(_("Command %s not understood"), keyword); continue; } @@ -639,7 +824,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 +865,7 @@ SET(NO_RCFILE); } } else { - parse_rcfile(rcstream); + parse_rcfile(rcstream, 0); fclose(rcstream); } } @@ -689,6 +874,32 @@ free(nanorc); #ifdef ENABLE_COLOR set_colorpairs(); + + if (ISSET(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: %s \"%s\"\n", + tmpsyntax->desc == NULL ? "default" : tmpsyntax->desc, + tmpcolor->flags.insensitive ? "icolor" : "color", + tmpcolor->start_regex); + else + printf("%s: %s start=\"%s\" end=\"%s\"\n", + tmpsyntax->desc == NULL ? "*" : tmpsyntax->desc, + tmpcolor->flags.insensitive ? "icolor" : "color", + tmpcolor->start_regex, tmpcolor->end_regex); + + /* TODO: display human readable color names */ + + } + printf("\n"); + } + exit(1); + } #endif }