int register_catalog_file_unlocked(const ichar *file, catalog_location where) { catalog_file **f = &catalog; catalog_file *cf; for (; *f; f = &(*f)->next) { cf = *f; if (istreq(cf->file, file)) return TRUE; /* existing, move? */ } cf = sgml_malloc(sizeof(*cf)); memset(cf, 0, sizeof(*cf)); cf->file = istrdup(file); if (!cf->file) sgml_nomem(); if (where == CTL_END) { cf->next = NULL; *f = cf; } else { cf->next = catalog; catalog = cf; } return TRUE; }
ichar * localpath(const ichar *ref, const ichar *name) { ichar *local; if (!ref || is_absolute_path(name)) local = istrdup(name); else { ichar buf[MAXPATHLEN]; DirName(ref, buf); istrcat(buf, DIRSEPSTR); istrcat(buf, name); local = istrdup(buf); } if (!local) sgml_nomem(); return local; }
static void load_one_catalogue(catalog_file * file) { FILE *src = wfopen(file->file, "r"); ichar buffer[2 * FILENAME_MAX]; ichar base[2 * FILENAME_MAX]; ichar *p; int t; catalogue_item_ptr this_item; int override = 0; if ( !src ) { gripe(NULL, ERC_NO_CATALOGUE, file->file); return; } (void) istrcpy(base, file->file); p = base + istrlen(base); while (p != base && !isDirSep(p[-1])) p--; for (;;) { t = scan(src, buffer, sizeof(buffer), 1); switch (t) { case CAT_BASE: if (scan(src, buffer, sizeof(buffer), 0) == EOF) break; (void) istrcpy(base, buffer); p = base + istrlen(base); if (p != base && !isDirSep(p[-1])) *p++ = '/'; continue; case CAT_OVERRIDE: if (scan(src, buffer, sizeof(buffer), 0) == EOF) break; override = towlower(buffer[0]) == 'y' ? CAT_OVERRIDE : 0; continue; case CAT_PUBLIC: case CAT_SYSTEM: case CAT_ENTITY: case CAT_DOCTYPE: this_item = sgml_malloc(sizeof *this_item); if (scan(src, buffer, sizeof buffer, 0) == EOF) break; if (t == CAT_PUBLIC) squish(buffer); this_item->next = 0; this_item->kind = t == CAT_SYSTEM ? t : t + override; this_item->target = istrdup(buffer); if (scan(src, buffer, sizeof buffer, 0) == EOF) break; if (is_absolute_path(buffer) || p == base) { this_item->replacement = istrdup(buffer); } else { (void) istrcpy(p, buffer); this_item->replacement = istrdup(base); } if (file->first_item == 0) { file->first_item = this_item; } else { file->last_item->next = this_item; } file->last_item = this_item; continue; case EOF: break; default: continue; } break; }
/* * Do grep on a single file. * Return true in any lines matched. * * We have two strategies: * The fast one is used when we have a single pattern with * a string known to occur in the pattern. We can then * do a BMG match on the whole buffer. * This is an order of magnitude faster. * Otherwise we split the buffer into lines, * and check for a match on each line. */ static int grep(int fd, const char *fn) { PATTERN *pp; off_t data_len; /* length of the data chunk */ off_t line_len; /* length of the current line */ off_t line_offset; /* current line's offset from the beginning */ off_t blkoffset; /* line_offset but context-compatible */ long long lineno, linenum; long long matches = 0; /* Number of matching lines */ long long conacnt = 0, conbcnt = 0; /* context line count */ int newlinep; /* 0 if the last line of file has no newline */ char *ptr, *ptrend, *prntptr, *prntptrend; char *nextptr = NULL, *nextend = NULL; char *conptr = NULL, *conptrend = NULL; char *matchptr = NULL; int conaprnt = 0, conbprnt = 0, lastmatch = 0; int nearmatch = conmatches ? 1 : 0; /* w/in N+1 of last match */ size_t prntlen; if (patterns == NULL) return (0); /* no patterns to match -- just return */ pp = patterns; if (use_bmg) { bmgcomp(pp->pattern, strlen(pp->pattern)); } if (use_wchar && outline == NULL) { outbuflen = BUFSIZE + 1; outline = malloc(sizeof (wchar_t) * outbuflen); if (outline == NULL) { (void) fprintf(stderr, gettext("%s: out of memory\n"), cmdname); exit(2); } } if (prntbuf == NULL) { prntbuflen = BUFSIZE; if ((prntbuf = malloc(prntbuflen + 1)) == NULL) { (void) fprintf(stderr, gettext("%s: out of memory\n"), cmdname); exit(2); } } if (conflag && (conbuf == NULL)) { conbuflen = BUFSIZE; if ((conbuf = malloc(BUFSIZE+1)) == NULL) { (void) fprintf(stderr, gettext("%s: out of memory\n"), cmdname); exit(2); } } blkoffset = line_offset = 0; lineno = 0; linenum = 1; newlinep = 1; data_len = 0; for (; ; ) { long count; off_t offset = 0; int eof = 0, rv = REG_NOMATCH; char separate; if (data_len == 0) { /* * If no data in the buffer, reset ptr */ ptr = prntbuf; if (conptr == NULL) conptrend = conptr = conbuf; } if (ptr == prntbuf) { /* * The current data chunk starts from prntbuf. * This means either the buffer has no data * or the buffer has no newline. * So, read more data from input. */ count = read(fd, ptr + data_len, prntbuflen - data_len); if (count < 0) { /* read error */ if (cflag) { if (outfn && !rflag) { (void) fprintf(stdout, "%s:", fn); } if (!qflag && !rflag) { (void) fprintf(stdout, "%lld\n", matches); } } return (0); } else if (count == 0) { /* no new data */ eof = 1; /* we never want to match EOF */ pp = (PATTERN *) !nvflag; if (data_len == 0) { /* end of file already reached */ if (conflag) { *conptrend = '\n'; goto L_next_line; } else { goto out; } } /* last line of file has no newline */ ptrend = ptr + data_len; newlinep = 0; goto L_start_process; } offset = data_len; data_len += count; } /* * Look for newline in the chunk * between ptr + offset and ptr + data_len - offset. */ ptrend = find_nl(ptr + offset, data_len - offset); if (ptrend == NULL) { /* no newline found in this chunk */ if (ptr > prntbuf) { /* * Move remaining data to the beginning * of the buffer. * Remaining data lie from ptr for * data_len bytes. */ (void) memmove(prntbuf, ptr, data_len); } if (data_len == prntbuflen) { /* * Not enough room in the buffer */ prntbuflen += BUFSIZE; prntbuf = realloc(prntbuf, prntbuflen + 1); if (prntbuf == NULL) { (void) fprintf(stderr, gettext("%s: out of memory\n"), cmdname); exit(2); } } ptr = prntbuf; /* read the next input */ continue; } L_start_process: /* * Beginning of the chunk: ptr * End of the chunk: ptr + data_len * Beginning of the line: ptr * End of the line: ptrend */ if (use_bmg) { /* * Use Boyer-Moore-Gosper algorithm to find out if * this chunk (not this line) contains the specified * pattern. If not, restart from the last line * of this chunk. */ char *bline; bline = bmgexec(ptr, ptr + data_len); if (bline == NULL) { /* * No pattern found in this chunk. * Need to find the last line * in this chunk. */ ptrend = rfind_nl(ptr, data_len); /* * When this chunk does not contain newline, * ptrend becomes NULL, which should happen * when the last line of file does not end * with a newline. At such a point, * newlinep should have been set to 0. * Therefore, just after jumping to * L_skip_line, the main for-loop quits, * and the line_len value won't be * used. */ line_len = ptrend - ptr; goto L_skip_line; } if (bline > ptrend) { /* * Pattern found not in the first line * of this chunk. * Discard the first line. */ line_len = ptrend - ptr; goto L_skip_line; } /* * Pattern found in the first line of this chunk. * Using this result. */ *ptrend = '\0'; line_len = ptrend - ptr; /* * before jumping to L_next_line, * need to handle xflag if specified */ if (xflag && (line_len != bmglen || strcmp(bmgpat, ptr) != 0)) { /* didn't match */ pp = NULL; } else { pp = patterns; /* to make it happen */ } goto L_next_line; } lineno++; /* * Line starts from ptr and ends at ptrend. * line_len will be the length of the line. */ *ptrend = '\0'; line_len = ptrend - ptr; /* * From now, the process will be performed based * on the line from ptr to ptrend. */ if (use_wchar) { size_t len; if (line_len >= outbuflen) { outbuflen = line_len + 1; outline = realloc(outline, sizeof (wchar_t) * outbuflen); if (outline == NULL) { (void) fprintf(stderr, gettext("%s: out of memory\n"), cmdname); exit(2); } } len = mbstowcs(outline, ptr, line_len); if (len == (size_t)-1) { (void) fprintf(stderr, gettext( "%s: input file \"%s\": line %lld: invalid multibyte character\n"), cmdname, fn, lineno); /* never match a line with invalid sequence */ goto L_skip_line; } outline[len] = L'\0'; if (iflag) { wchar_t *cp; for (cp = outline; *cp != '\0'; cp++) { *cp = towlower((wint_t)*cp); } } if (xflag) { for (pp = patterns; pp; pp = pp->next) { if (outline[0] == pp->wpattern[0] && wcscmp(outline, pp->wpattern) == 0) { /* matched */ rv = REG_OK; break; } } } else { for (pp = patterns; pp; pp = pp->next) { if (wcswcs(outline, pp->wpattern) != NULL) { /* matched */ rv = REG_OK; break; } } } } else if (Fflag) { /* fgrep in byte-oriented handling */ char *fptr; if (iflag) { fptr = istrdup(ptr); } else { fptr = ptr; } if (xflag) { /* fgrep -x */ for (pp = patterns; pp; pp = pp->next) { if (fptr[0] == pp->pattern[0] && strcmp(fptr, pp->pattern) == 0) { /* matched */ rv = REG_OK; break; } } } else { for (pp = patterns; pp; pp = pp->next) { if (strstr(fptr, pp->pattern) != NULL) { /* matched */ rv = REG_OK; break; } } } } else { /* grep or egrep */ for (pp = patterns; pp; pp = pp->next) { rv = regexec(&pp->re, ptr, 0, NULL, 0); if (rv == REG_OK) { /* matched */ break; } switch (rv) { case REG_NOMATCH: break; case REG_ECHAR: (void) fprintf(stderr, gettext( "%s: input file \"%s\": line %lld: invalid multibyte character\n"), cmdname, fn, lineno); break; default: (void) regerror(rv, &pp->re, errstr, sizeof (errstr)); (void) fprintf(stderr, gettext( "%s: input file \"%s\": line %lld: %s\n"), cmdname, fn, lineno, errstr); exit(2); } } } /* * Context is set up as follows: * For a 'Before' context, we maintain a set of pointers * containing 'N' lines of context. If the current number of * lines contained is greater than N, and N isn't a match, the * start pointer is moved forward to the next newline. * * If we ever find a match, we print out immediately. * 'nearmatch' tells us if we're within N+1 lines of the last * match ; if we are, and we find another match, we don't * separate the matches. 'nearmatch' becomes false when * a line gets rotated out of the context. * * For an 'After' context, we simply wait until we've found a * match, then create a context N+1 lines big. If we don't find * a match within the context, we print out the current context. * Otherwise, we save a reference to the new matching line, * print out the other context, and reset our context pointers * to the new matching line. * * 'nearmatch' becomes false when we find a non-matching line * that isn't a part of any context. * * A full-context is implemented as a combination of the * 'Before' and 'After' context logic. Before we find a match, * we follow the Before logic. When we find a match, we * follow the After logic. 'nearmatch' is handled by the Before * logic. */ if (!conflag) goto L_next_line; if (line_len + (conptrend - conbuf) > conbuflen) { char *oldconbuf = conbuf; char *oldconptr = conptr; long tmp = matchptr - conptr; conbuflen += BUFSIZE; conbuf = realloc(conbuf, conbuflen + 1); if (conbuf == NULL) { (void) fprintf(stderr, gettext("%s: out of memory\n"), cmdname); exit(2); } conptr = conbuf + (conptr - oldconbuf); conptrend = conptr + (conptrend - oldconptr); if (matchptr) matchptr = conptr + tmp; } (void) memcpy((conptrend > conptr) ? conptrend + 1 : conptrend, ptr, line_len); conptrend += line_len + (conptrend > conptr); *conptrend = '\n'; if (!nvflag == rv) { /* matched */ if (lastmatch) { if (conflag & AFTER) { conaprnt = 1; nextend = conptrend; conptrend = conptr + lastmatch; nextptr = conptrend + 1; *nextend = '\n'; } } else { if (conflag == AFTER) { conptr = conptrend - (line_len); linenum = lineno; blkoffset = line_offset; } blkoffset = line_offset - (conptrend - conptr - line_len); } if (conflag == BEFORE) conbprnt = 1; lastmatch = conptrend - conptr; goto L_next_line; } if (!lastmatch) { if (conflag & BEFORE) { if (conbcnt >= conblen) { char *tmp = conptr; conptr = find_nl(conptr, conptrend - conptr) + 1; if (bflag) blkoffset += conptr - tmp; linenum++; nearmatch = 1; } else { conbcnt++; } } if (conflag == AFTER) nearmatch = 1; } else { if (++conacnt >= conalen && !conaprnt && conalen) conaprnt = 1; else lastmatch = conptrend - conptr; } L_next_line: /* * Here, if pp points to non-NULL, something has been matched * to the pattern. */ if (nvflag == (pp != NULL)) { matches++; if (!nextend) matchptr = conflag ? conptrend : ptrend; } /* * Set up some print context so that we can treat * single-line matches as a zero-N context. * Apply CLI flags to each line of the context. * * For context, we only print if we both have a match and are * either at the end of the data stream, or we've previously * declared that we want to print for a particular context. */ if (lastmatch && (eof || conaprnt || conbprnt)) { /* * We'd normally do this earlier, but we had to * escape early because we reached the end of the data. */ if (eof && nextptr) conptrend = nextend; prntlen = conptrend - conptr + 1; prntptrend = prntptr = conptr; if (conmatches++ && nearmatch && !cflag) (void) fwrite("--\n", 1, 3, stdout); } else if (!conflag && nvflag == (pp != NULL)) { *ptrend = '\n'; prntlen = line_len + 1; prntptrend = prntptr = ptr; linenum = lineno; blkoffset = line_offset; } else if (eof) { /* No match and no more data */ goto out; } else { /* No match, or we're not done building context */ goto L_skip_line; } while ((prntptrend = find_nl(prntptrend+1, prntlen)) != NULL) { /* * GNU grep uses '-' for context lines and ':' for * matching lines, so replicate that here. */ if (prntptrend == matchptr) { if (eof && nextptr) { matchptr = nextend; nextptr = NULL; } else { matchptr = NULL; } separate = ':'; } else { separate = '-'; } /* * Handle q, l, and c flags. */ if (qflag) { /* no need to continue */ /* * End of this line is ptrend. * We have read up to ptr + data_len. */ off_t pos; pos = ptr + data_len - (ptrend + 1); (void) lseek(fd, -pos, SEEK_CUR); exit(0); } if (lflag) { (void) printf("%s\n", fn); goto out; } if (!cflag) { if (Hflag || outfn) { (void) printf("%s%c", fn, separate); } if (bflag) { (void) printf("%lld%c", (offset_t) (blkoffset / BSIZE), separate); } if (nflag) { (void) printf("%lld%c", linenum, separate); } (void) fwrite(prntptr, 1, prntptrend - prntptr + 1, stdout); } if (ferror(stdout)) { return (0); } linenum++; prntlen -= prntptrend - prntptr + 1; blkoffset += prntptrend - prntptr + 1; prntptr = prntptrend + 1; } if (eof) goto out; /* * Update context buffer and variables post-print */ if (conflag) { conptr = conbuf; conaprnt = conbprnt = 0; nearmatch = 0; conacnt = conbcnt = 0; if (nextptr) { (void) memmove(conbuf, nextptr, nextend - nextptr + 1); blkoffset += nextptr - conptrend - 1; conptrend = conptr + (nextend - nextptr); matchptr = conptrend; linenum = lineno; lastmatch = conptrend - conptr; } else { conptrend = conptr; conacnt = 0; lastmatch = 0; } nextptr = nextend = NULL; } L_skip_line: if (!newlinep) break; data_len -= line_len + 1; line_offset += line_len + 1; ptr = ptrend + 1; } out: if (cflag) { if (Hflag || outfn) { (void) printf("%s:", fn); } if (!qflag) { (void) printf("%lld\n", matches); } } return (matches != 0); }