/* Parse the header-line regexes that may influence the choice of syntax. */ void parse_header_exp(char *ptr) { regexlisttype *endheader = NULL; assert(ptr != NULL); if (syntaxes == NULL) { rcfile_error( N_("Cannot add a header regex without a syntax command")); return; } if (*ptr == '\0') { rcfile_error(N_("Missing regex string")); return; } while (*ptr != '\0') { const char *regexstring; regexlisttype *newheader; if (*ptr != '"') { rcfile_error( N_("Regex strings must begin and end with a \" character")); ptr = parse_next_regex(ptr); continue; } ptr++; regexstring = ptr; ptr = parse_next_regex(ptr); if (ptr == NULL) break; newheader = (regexlisttype *)nmalloc(sizeof(regexlisttype)); /* Save the regex string if it's valid. */ if (nregcomp(regexstring, 0)) { newheader->ext_regex = mallocstrcpy(NULL, regexstring); newheader->ext = NULL; if (endheader == NULL) endsyntax->headers = newheader; else endheader->next = newheader; endheader = newheader; endheader->next = NULL; } else free(newheader); } }
/* Parse the headers (1st line) of the file which may influence the regex used. */ void parse_headers(char *ptr) { char *regstr; assert(ptr != NULL); if (syntaxes == NULL) { rcfile_error( N_("Cannot add a header regex without a syntax command")); return; } if (*ptr == '\0') { rcfile_error(N_("Missing regex string")); return; } /* Now for the fun part. Start adding regexes to individual strings * in the colorstrings array, woo! */ while (ptr != NULL && *ptr != '\0') { exttype *newheader; /* The new color structure. */ if (*ptr != '"') { rcfile_error( N_("Regex strings must begin and end with a \" character")); ptr = parse_next_regex(ptr); continue; } ptr++; regstr = ptr; ptr = parse_next_regex(ptr); if (ptr == NULL) break; newheader = (exttype *)nmalloc(sizeof(exttype)); /* Save the regex string if it's valid */ if (nregcomp(regstr, 0)) { newheader->ext_regex = mallocstrcpy(NULL, regstr); newheader->ext = NULL; newheader->next = NULL; #ifdef DEBUG fprintf(stderr, "Starting a new header entry: %s\n", newheader->ext_regex); #endif if (endheader == NULL) { endsyntax->headers = newheader; } else { endheader->next = newheader; } endheader = newheader; } else free(newheader); } }
/* Parse the color string in the line at ptr, and add it to the current * file's associated colors. If icase is TRUE, treat the color string * as case insensitive. */ void parse_colors(char *ptr, bool icase) { short fg, bg; bool bright = FALSE, no_fgcolor = FALSE; char *fgstr; assert(ptr != NULL); if (syntaxes == NULL) { rcfile_error( N_("Cannot add a color command without a syntax command")); return; } if (*ptr == '\0') { rcfile_error(N_("Missing color name")); return; } fgstr = ptr; ptr = parse_next_word(ptr); if (strchr(fgstr, ',') != NULL) { char *bgcolorname; strtok(fgstr, ","); bgcolorname = strtok(NULL, ","); if (bgcolorname == NULL) { /* If we have a background color without a foreground color, * parse it properly. */ bgcolorname = fgstr + 1; no_fgcolor = TRUE; } if (strncasecmp(bgcolorname, "bright", 6) == 0) { rcfile_error( N_("Background color \"%s\" cannot be bright"), bgcolorname); return; } bg = color_to_short(bgcolorname, &bright); } else bg = -1; if (!no_fgcolor) { fg = color_to_short(fgstr, &bright); /* Don't try to parse screwed-up foreground colors. */ if (fg == -1) return; } else fg = -1; if (*ptr == '\0') { rcfile_error(N_("Missing regex string")); return; } /* Now for the fun part. Start adding regexes to individual strings * in the colorstrings array, woo! */ while (ptr != NULL && *ptr != '\0') { colortype *newcolor; /* The new color structure. */ bool cancelled = FALSE; /* The start expression was bad. */ bool expectend = FALSE; /* Do we expect an end= line? */ if (strncasecmp(ptr, "start=", 6) == 0) { ptr += 6; expectend = TRUE; } if (*ptr != '"') { rcfile_error( N_("Regex strings must begin and end with a \" character")); ptr = parse_next_regex(ptr); continue; } ptr++; fgstr = ptr; ptr = parse_next_regex(ptr); if (ptr == NULL) break; newcolor = (colortype *)nmalloc(sizeof(colortype)); /* Save the starting regex string if it's valid, and set up the * color information. */ if (nregcomp(fgstr, icase ? REG_ICASE : 0)) { newcolor->fg = fg; newcolor->bg = bg; newcolor->bright = bright; newcolor->icase = icase; newcolor->start_regex = mallocstrcpy(NULL, fgstr); newcolor->start = NULL; newcolor->end_regex = NULL; newcolor->end = NULL; newcolor->next = NULL; if (endcolor == NULL) { endsyntax->color = newcolor; #ifdef DEBUG fprintf(stderr, "Starting a new colorstring for fg %hd, bg %hd\n", fg, bg); #endif } else { #ifdef DEBUG fprintf(stderr, "Adding new entry for fg %hd, bg %hd\n", fg, bg); #endif endcolor->next = newcolor; } endcolor = newcolor; } else { free(newcolor); cancelled = TRUE; } if (expectend) { if (ptr == NULL || strncasecmp(ptr, "end=", 4) != 0) { rcfile_error( N_("\"start=\" requires a corresponding \"end=\"")); return; } ptr += 4; if (*ptr != '"') { rcfile_error( N_("Regex strings must begin and end with a \" character")); continue; } ptr++; fgstr = ptr; ptr = parse_next_regex(ptr); if (ptr == NULL) break; /* If the start regex was invalid, skip past the end regex to * stay in sync. */ if (cancelled) continue; /* Save the ending regex string if it's valid. */ newcolor->end_regex = (nregcomp(fgstr, icase ? REG_ICASE : 0)) ? mallocstrcpy(NULL, fgstr) : NULL; /* Lame way to skip another static counter */ newcolor->id = endsyntax->nmultis; endsyntax->nmultis++; } } }
/* Parse the next syntax string from the line at ptr, and add it to the * global list of color syntaxes. */ void parse_syntax(char *ptr) { const char *fileregptr = NULL, *nameptr = NULL; syntaxtype *tmpsyntax; exttype *endext = NULL; /* The end of the extensions list for this syntax. */ assert(ptr != NULL); if (*ptr == '\0') { rcfile_error(N_("Missing syntax name")); return; } if (*ptr != '"') { rcfile_error( N_("Regex strings must begin and end with a \" character")); return; } ptr++; nameptr = ptr; ptr = parse_next_regex(ptr); if (ptr == NULL) return; /* Search for a duplicate syntax name. If we find one, free it, so * that we always use the last syntax with a given name. */ for (tmpsyntax = syntaxes; tmpsyntax != NULL; tmpsyntax = tmpsyntax->next) { if (strcmp(nameptr, tmpsyntax->desc) == 0) { syntaxtype *prev_syntax = tmpsyntax; tmpsyntax = tmpsyntax->next; free(prev_syntax); break; } } if (syntaxes == NULL) { syntaxes = (syntaxtype *)nmalloc(sizeof(syntaxtype)); endsyntax = syntaxes; } else { endsyntax->next = (syntaxtype *)nmalloc(sizeof(syntaxtype)); endsyntax = endsyntax->next; #ifdef DEBUG fprintf(stderr, "Adding new syntax after first one\n"); #endif } endsyntax->desc = mallocstrcpy(NULL, nameptr); endsyntax->color = NULL; endcolor = NULL; endheader = NULL; endsyntax->extensions = NULL; endsyntax->headers = NULL; endsyntax->next = NULL; endsyntax->nmultis = 0; #ifdef DEBUG fprintf(stderr, "Starting a new syntax type: \"%s\"\n", nameptr); #endif /* The "none" syntax is the same as not having a syntax at all, so * we can't assign any extensions or colors to it. */ if (strcmp(endsyntax->desc, "none") == 0) { rcfile_error(N_("The \"none\" syntax is reserved")); return; } /* The default syntax should have no associated extensions. */ if (strcmp(endsyntax->desc, "default") == 0 && *ptr != '\0') { rcfile_error( N_("The \"default\" syntax must take no extensions")); return; } /* Now load the extensions into their part of the struct. */ while (*ptr != '\0') { exttype *newext; /* The new extension structure. */ while (*ptr != '"' && *ptr != '\0') ptr++; if (*ptr == '\0') return; ptr++; fileregptr = ptr; ptr = parse_next_regex(ptr); if (ptr == NULL) break; newext = (exttype *)nmalloc(sizeof(exttype)); /* Save the extension regex if it's valid. */ if (nregcomp(fileregptr, REG_NOSUB)) { newext->ext_regex = mallocstrcpy(NULL, fileregptr); newext->ext = NULL; if (endext == NULL) endsyntax->extensions = newext; else endext->next = newext; endext = newext; endext->next = NULL; } else free(newext); } }
/* Parse the next syntax string from the line at ptr, and add it to the * global list of color syntaxes. */ void parse_magictype(char *ptr) { #ifdef HAVE_LIBMAGIC const char *fileregptr = NULL; exttype *endext = NULL; assert(ptr != NULL); if (syntaxes == NULL) { rcfile_error( N_("Cannot add a magic string regex without a syntax command")); return; } if (*ptr == '\0') { rcfile_error(N_("Missing magic string name")); return; } if (*ptr != '"') { rcfile_error( N_("Regex strings must begin and end with a \" character")); return; } #ifdef DEBUG fprintf(stderr, "Starting a magic type: \"%s\"\n", ptr); #endif /* Now load the extensions into their part of the struct. */ while (*ptr != '\0') { exttype *newext; /* The new extension structure. */ while (*ptr != '"' && *ptr != '\0') ptr++; if (*ptr == '\0') return; ptr++; fileregptr = ptr; ptr = parse_next_regex(ptr); if (ptr == NULL) break; newext = (exttype *)nmalloc(sizeof(exttype)); /* Save the regex if it's valid. */ if (nregcomp(fileregptr, REG_NOSUB)) { newext->ext_regex = mallocstrcpy(NULL, fileregptr); newext->ext = NULL; if (endext == NULL) endsyntax->magics = newext; else endext->next = newext; endext = newext; endext->next = NULL; } else free(newext); } #endif /* HAVE_LIBMAGIC */ }
/* Parse the magic regexes that may influence the choice of syntax. */ void parse_magic_exp(char *ptr) { regexlisttype *endmagic = NULL; assert(ptr != NULL); if (syntaxes == NULL) { rcfile_error( N_("Cannot add a magic string regex without a syntax command")); return; } if (*ptr == '\0') { rcfile_error(N_("Missing magic string name")); return; } if (*ptr != '"') { rcfile_error( N_("Regex strings must begin and end with a \" character")); return; } #ifdef DEBUG fprintf(stderr, "Starting a magic type: \"%s\"\n", ptr); #endif /* Now load the magic regexes into their part of the struct. */ while (*ptr != '\0') { const char *regexstring; regexlisttype *newmagic; while (*ptr != '"' && *ptr != '\0') ptr++; if (*ptr == '\0') return; ptr++; regexstring = ptr; ptr = parse_next_regex(ptr); if (ptr == NULL) break; newmagic = (regexlisttype *)nmalloc(sizeof(regexlisttype)); /* Save the regex string if it's valid. */ if (nregcomp(regexstring, REG_NOSUB)) { newmagic->ext_regex = mallocstrcpy(NULL, regexstring); newmagic->ext = NULL; if (endmagic == NULL) endsyntax->magics = newmagic; else endmagic->next = newmagic; endmagic = newmagic; endmagic->next = NULL; } else free(newmagic); } }
/* Parse the color string in the line at ptr, and add it to the current * file's associated colors. If icase is TRUE, treat the color string * as case insensitive. */ void parse_colors(char *ptr, bool icase) { short fg, bg; bool bright = FALSE; char *fgstr; assert(ptr != NULL); if (syntaxes == NULL) { rcfile_error( N_("Cannot add a color command without a syntax command")); return; } if (*ptr == '\0') { rcfile_error(N_("Missing color name")); return; } fgstr = ptr; ptr = parse_next_word(ptr); if (!parse_color_names(fgstr, &fg, &bg, &bright)) return; if (*ptr == '\0') { rcfile_error(N_("Missing regex string")); return; } /* Now for the fun part. Start adding regexes to individual strings * in the colorstrings array, woo! */ while (ptr != NULL && *ptr != '\0') { colortype *newcolor; /* The container for a color plus its regexes. */ bool cancelled = FALSE; /* The start expression was bad. */ bool expectend = FALSE; /* Do we expect an end= line? */ if (strncasecmp(ptr, "start=", 6) == 0) { ptr += 6; expectend = TRUE; } if (*ptr != '"') { rcfile_error( N_("Regex strings must begin and end with a \" character")); ptr = parse_next_regex(ptr); continue; } ptr++; fgstr = ptr; ptr = parse_next_regex(ptr); if (ptr == NULL) break; newcolor = (colortype *)nmalloc(sizeof(colortype)); /* Save the starting regex string if it's valid, and set up the * color information. */ if (nregcomp(fgstr, icase ? REG_ICASE : 0)) { newcolor->fg = fg; newcolor->bg = bg; newcolor->bright = bright; newcolor->icase = icase; newcolor->start_regex = mallocstrcpy(NULL, fgstr); newcolor->start = NULL; newcolor->end_regex = NULL; newcolor->end = NULL; newcolor->next = NULL; if (endcolor == NULL) { endsyntax->color = newcolor; #ifdef DEBUG fprintf(stderr, "Starting a new colorstring for fg %hd, bg %hd\n", fg, bg); #endif } else { #ifdef DEBUG fprintf(stderr, "Adding new entry for fg %hd, bg %hd\n", fg, bg); #endif /* Need to recompute endcolor now so we can extend * colors to syntaxes. */ for (endcolor = endsyntax->color; endcolor->next != NULL; endcolor = endcolor->next) ; endcolor->next = newcolor; } endcolor = newcolor; } else { free(newcolor); cancelled = TRUE; } if (expectend) { if (ptr == NULL || strncasecmp(ptr, "end=", 4) != 0) { rcfile_error( N_("\"start=\" requires a corresponding \"end=\"")); return; } ptr += 4; if (*ptr != '"') { rcfile_error( N_("Regex strings must begin and end with a \" character")); continue; } ptr++; fgstr = ptr; ptr = parse_next_regex(ptr); if (ptr == NULL) break; /* If the start regex was invalid, skip past the end regex * to stay in sync. */ if (cancelled) continue; /* Save the ending regex string if it's valid. */ newcolor->end_regex = (nregcomp(fgstr, icase ? REG_ICASE : 0)) ? mallocstrcpy(NULL, fgstr) : NULL; /* Lame way to skip another static counter. */ newcolor->id = endsyntax->nmultis; endsyntax->nmultis++; } } }
/* Read regex strings enclosed in double quotes from the line pointed at * by ptr, and store them quoteless in the passed storage place. */ void grab_and_store(const char *kind, char *ptr, regexlisttype **storage) { regexlisttype *lastthing; if (!opensyntax) { rcfile_error( N_("A '%s' command requires a preceding 'syntax' command"), kind); return; } /* The default syntax doesn't take any file matching stuff. */ if (strcmp(live_syntax->name, "default") == 0 && *ptr != '\0') { rcfile_error( N_("The \"default\" syntax does not accept '%s' regexes"), kind); return; } if (*ptr == '\0') { rcfile_error(N_("Missing regex string after '%s' command"), kind); return; } lastthing = *storage; /* If there was an earlier command, go to the last of those regexes. */ while (lastthing != NULL && lastthing->next != NULL) lastthing = lastthing->next; /* Now gather any valid regexes and add them to the linked list. */ while (*ptr != '\0') { const char *regexstring; regexlisttype *newthing; if (*ptr != '"') { rcfile_error( N_("Regex strings must begin and end with a \" character")); return; } regexstring = ++ptr; ptr = parse_next_regex(ptr); if (ptr == NULL) return; /* If the regex string is malformed, skip it. */ if (!nregcomp(regexstring, NANO_REG_EXTENDED | REG_NOSUB)) continue; /* Copy the regex into a struct, and hook this in at the end. */ newthing = (regexlisttype *)nmalloc(sizeof(regexlisttype)); newthing->full_regex = mallocstrcpy(NULL, regexstring); newthing->next = NULL; if (lastthing == NULL) *storage = newthing; else lastthing->next = newthing; lastthing = newthing; } }
/* Parse the color string in the line at ptr, and add it to the current * file's associated colors. rex_flags are the regex compilation flags * to use, excluding or including REG_ICASE for case (in)sensitivity. */ void parse_colors(char *ptr, int rex_flags) { short fg, bg; bool bright = FALSE; char *fgstr; assert(ptr != NULL); if (!opensyntax) { rcfile_error( N_("A '%s' command requires a preceding 'syntax' command"), "color"); return; } if (*ptr == '\0') { rcfile_error(N_("Missing color name")); return; } fgstr = ptr; ptr = parse_next_word(ptr); if (!parse_color_names(fgstr, &fg, &bg, &bright)) return; if (*ptr == '\0') { rcfile_error(N_("Missing regex string after '%s' command"), "color"); return; } /* Now for the fun part. Start adding regexes to individual strings * in the colorstrings array, woo! */ while (ptr != NULL && *ptr != '\0') { colortype *newcolor = NULL; /* The container for a color plus its regexes. */ bool goodstart; /* Whether the start expression was valid. */ bool expectend = FALSE; /* Whether to expect an end= line. */ if (strncasecmp(ptr, "start=", 6) == 0) { ptr += 6; expectend = TRUE; } if (*ptr != '"') { rcfile_error( N_("Regex strings must begin and end with a \" character")); ptr = parse_next_regex(ptr); continue; } fgstr = ++ptr; ptr = parse_next_regex(ptr); if (ptr == NULL) break; goodstart = nregcomp(fgstr, rex_flags); /* If the starting regex is valid, initialize a new color struct, * and hook it in at the tail of the linked list. */ if (goodstart) { newcolor = (colortype *)nmalloc(sizeof(colortype)); newcolor->fg = fg; newcolor->bg = bg; newcolor->bright = bright; newcolor->rex_flags = rex_flags; newcolor->start_regex = mallocstrcpy(NULL, fgstr); newcolor->start = NULL; newcolor->end_regex = NULL; newcolor->end = NULL; newcolor->next = NULL; #ifdef DEBUG fprintf(stderr, "Adding an entry for fg %hd, bg %hd\n", fg, bg); #endif if (lastcolor == NULL) live_syntax->color = newcolor; else lastcolor->next = newcolor; lastcolor = newcolor; } if (!expectend) continue; if (ptr == NULL || strncasecmp(ptr, "end=", 4) != 0) { rcfile_error(N_("\"start=\" requires a corresponding \"end=\"")); return; } ptr += 4; if (*ptr != '"') { rcfile_error(N_("Regex strings must begin and end with a \" character")); continue; } fgstr = ++ptr; ptr = parse_next_regex(ptr); if (ptr == NULL) break; /* If the start regex was invalid, skip past the end regex * to stay in sync. */ if (!goodstart) continue; /* If it's valid, save the ending regex string. */ if (nregcomp(fgstr, rex_flags)) newcolor->end_regex = mallocstrcpy(NULL, fgstr); /* Lame way to skip another static counter. */ newcolor->id = live_syntax->nmultis; live_syntax->nmultis++; } }