static int matchdir(struct dirbuf *np, const char *pattern) { struct dirbuf name = *np; DIR *dir; struct dirent *dp; int nmatches = 0; /* If path is not empty, append a path separator */ if (!dirbuf_addslash(&name)) return 0; if (!(dir = opendir(dirbuf_as_path(&name)))) return 0; while ((dp = readdir(dir)) != NULL) { if (dp->d_name[0] == '.' && pattern[0] != '.') continue; DEBUG(("* matching \"%s\"\n", dp->d_name)); if (matchfile(&name, dp->d_name, pattern)) nmatches++; } closedir(dir); return nmatches; }
void main(int argc, char *argv[]) { Reprog *exp; char *pattern = 0; int n = 1000; char *line; int xflag = 0; int iflag = 0; Biobuf bin; Biobuf *b = &bin; char buf[256]; ARGBEGIN { case 'l': case 'n': n=atoi(EARGF(usage())); break; case 'e': pattern = strdup(EARGF(usage())); break; case 'f': stem = strdup(EARGF(usage())); break; case 's': suffix = strdup(EARGF(usage())); break; case 'x': xflag++; break; case 'i': iflag++; break; default: usage(); break; } ARGEND; if(argc < 0 || argc > 1) usage(); if(argc != 0) { b = Bopen(argv[0], OREAD); if(b == nil) { fprint(2, "split: can't open %s: %r\n", argv[0]); exits("open"); } } else Binit(b, 0, OREAD); if(pattern) { Resub match[2]; if(!(exp = regcomp(iflag? fold(pattern, strlen(pattern)): pattern))) badexp(); memset(match, 0, sizeof match); matchfile(match); while((line=Brdline(b,'\n')) != 0) { memset(match, 0, sizeof match); line[Blinelen(b)-1] = 0; if(regexec(exp, iflag? fold(line, Blinelen(b)-1): line, match, 2)) { if(matchfile(match) && xflag) continue; } else if(output == 0) nextfile(); /* at most once */ Bwrite(output, line, Blinelen(b)-1); Bputc(output, '\n'); } } else { int linecnt = n; while((line=Brdline(b,'\n')) != 0) { if(++linecnt > n) { nextfile(); linecnt = 1; } Bwrite(output, line, Blinelen(b)); } /* * in case we didn't end with a newline, tack whatever's * left onto the last file */ while((n = Bread(b, buf, sizeof(buf))) > 0) Bwrite(output, buf, n); } if(b != nil) Bterm(b); exits(0); }
Address address(Addr *ap, Address a, int sign) { File *f = a.f; Address a1, a2; do{ switch(ap->type){ case 'l': case '#': a = (*(ap->type=='#'?charaddr:lineaddr))(ap->num, a, sign); break; case '.': a = f->dot; break; case '$': a.r.p1 = a.r.p2 = f->Buffer.nc; break; case '\'': a.r = f->mark; break; case '?': sign = -sign; if(sign == 0) sign = -1; /* fall through */ case '/': nextmatch(f, ap->are, sign>=0? a.r.p2 : a.r.p1, sign); a.r = sel.p[0]; break; case '"': a = matchfile(ap->are)->dot; f = a.f; if(f->unread) load(f); break; case '*': a.r.p1 = 0, a.r.p2 = f->Buffer.nc; return a; case ',': case ';': if(ap->left) a1 = address(ap->left, a, 0); else a1.f = a.f, a1.r.p1 = a1.r.p2 = 0; if(ap->type == ';'){ f = a1.f; a = a1; f->dot = a1; } if(ap->next) a2 = address(ap->next, a, 0); else a2.f = a.f, a2.r.p1 = a2.r.p2 = f->Buffer.nc; if(a1.f != a2.f) error(Eorder); a.f = a1.f, a.r.p1 = a1.r.p1, a.r.p2 = a2.r.p2; if(a.r.p2 < a.r.p1) error(Eorder); return a; case '+': case '-': sign = 1; if(ap->type == '-') sign = -1; if(ap->next==0 || ap->next->type=='+' || ap->next->type=='-') a = lineaddr(1L, a, sign); break; default: panic("address"); return a; } }while(ap = ap->next); /* assign = */ return a; }
/* * This one deals with the expansion of {...} expressions. * This is complicated by nesting ([...] and {...} can occur * within). * * We do this in two passes. If the pattern is * {alt1,alt2,...,altN}rest * then we first go over the pattern finding "rest". Once we have * it, we make a second pass, this time matching the given filename * against "altK" concatenated with "rest" for each alternative "altK". */ static int dobraces(struct dirbuf *np, const char *fname, const char *pattern) { const char *begin, *tail = NULL; char patbuf[1024], stack[MAXNEST], pc; unsigned int nc, match = 0, nsp = 0; if (strlen(pattern) >= sizeof(patbuf)) return 0; /* Remember where our pattern begins */ begin = pattern; again: /* We've scanned past the opening brace, but it's there, * so count it */ stack[0] = RIGHTCURLY; nsp = 1; nc = 0; while (*pattern) { pc = *pattern++; /* Do we have a complete alternative? */ if (nsp == 1 && (pc == COMMA || pc == RIGHTCURLY)) { if (tail != NULL) { struct dirbuf name = *np; ASSERT(nc+strlen(tail) < sizeof(patbuf)); patbuf[nc] = '\0'; strcat(patbuf, tail); if (matchfile(&name, fname, patbuf)) match++; } /* Have we closed the outermost bracket? */ if (pc == RIGHTCURLY) { nsp--; break; } /* Start scanning for the next alternative */ nc = 0; continue; } /* Nested character classes/alternatives */ if (pc == LEFTCURLY || pc == LEFTBLOCKY) { if (nsp >= MAXNEST) return 0; stack[nsp++] = (pc == LEFTCURLY)? RIGHTCURLY : RIGHTBLOCKY; } else if (pc == RIGHTCURLY || pc == RIGHTBLOCKY) { /* Make sure closing bracket/brace * matches opening one */ if (!nsp || stack[--nsp] != pc) return 0; } /* Copy to pattern buffer */ ASSERT(nc < sizeof(patbuf)-2); patbuf[nc++] = pc; patbuf[nc] = '\0'; } /* No closing brace? Trouble. */ if (nsp != 0) return 0; if (tail == NULL) { /* We have the remainder. Keep it and start over */ tail = pattern; pattern = begin; goto again; } return match; }
static int matchfile(struct dirbuf *np, const char *fname, const char *pattern) { struct dirbuf name = *np; unsigned char pc, fc; /* DEBUG(("* try \"%s\" ~ \"%s\"\n", fname, pattern)); */ while (*pattern && *pattern != '/') { pc = *pattern++; fc = *fname; switch (pc) { case '?': if (!fc || !dirbuf_appendc(&name, fc)) return 0; fname++; break; /* Match 0 or more characters. Try to match greedily * i.e. as many characters as possible. */ case '*': { struct dirbuf temp; unsigned int n, ok = 0; n = strlen(fname); do { temp = name; if (dirbuf_appends(&temp, fname, n)) { ok = matchfile(&temp, fname + n, pattern); } } while (!ok && n--); return ok; } /* Match character range */ case LEFTBLOCKY: { unsigned char from, to; int ok = 0; if (fc == '\0') return 0; while (1) { to = from = *pattern++; if (from == RIGHTBLOCKY) break; if (from == '\0') return 0; if (*pattern == '-') { pattern++; to = *pattern++; if (to == '\0') return 0; } if (from <= fc && fc <= to) ok = 1; } if (!ok || !dirbuf_appendc(&name, fc)) return 0; fname++; break; } case LEFTCURLY: /* Handle braces - icky ugly and bad */ return dobraces(&name, fname, pattern); case '\\': if ((fc = *++fname) == '\0') return 0; /* fallthru */ default: if (pc != fc || !dirbuf_appendc(&name, fc)) return 0; fname++; break; } } /* Pattern exhausted - make sure we've matched the full * filename! */ if (*fname != '\0') return 0; return doglob(&name, pattern); }
/* * Note: openinfo is a function for reading info files, and putting * uncompressed content into a temporary filename. For a flexibility, there * are two temporary files supported, i.e. one for keeping opened info file, * and second for i.e. regexp search across info nodes, which are in other * info-subfiles. The temporary file 1 is refrenced by number=0, and file 2 by * number=1 Openinfo by default first tries the path stored in char * *filenameprefix and then in the rest of userdefined paths. */ FILE * openinfo(char *filename, int number) { FILE *id = NULL; #define BUF_LEN 1024 char *buf = xmalloc(BUF_LEN); /* holds local copy of filename */ char *bufend; /* points at the trailing 0 of initial name */ char command[1128]; /* holds command to evaluate for decompression of file */ int i, j; char *tmpfilename; if ((strncmp(filename, "dir", 3)==0) && !isalnum(filename[3])) { xfree(buf); return opendirfile(number); } if (number == 0) /* initialize tmp filename for file 1 */ { if (tmpfilename1) { unlink(tmpfilename1); /* erase old tmpfile */ free(tmpfilename1); } tmpfilename1 = make_tempfile(); tmpfilename = tmpfilename1; /* later we will refere only to tmp1 */ } else /* initialize tmp filename for file 2 */ { if (tmpfilename2) { unlink(tmpfilename2); /* erase old tmpfile */ free(tmpfilename2); } tmpfilename2 = make_tempfile(); tmpfilename = tmpfilename2; /* later we will refere only to tmp2 */ } for (i = -2; i < infopathcount; i++) /* go through all paths */ { if (i < 0) { /* * no filenameprefix, we don't navigate around any specific * infopage set, so simply scan all directories for a hit */ if (!filenameprefix) continue; /* build a filename: First (i == -2) try filenameprefix/filename, * then try with a .info appended */ if (i == -2) snprintf(buf, BUF_LEN, "%s/%s", filenameprefix, basename(filename)); else snprintf(buf, BUF_LEN, "%s/%s.info", filenameprefix, basename(filename)); } else { /* build a filename */ strcpy(buf, infopaths[i]); /* no match found in this directory */ if (! matchfile(&buf, filename)) continue; } bufend = buf; /* remember the bufend to make it possible later to glue compression * suffixes. */ bufend += strlen(buf); for (j = 0; j < SuffixesNumber; j++) /* go through all suffixes */ { strcat(buf, suffixes[j].suffix); if ((id = fopen(buf, "r")) != NULL) { fclose(id); clearfilenameprefix(); filenameprefix = strdup(buf); { /* small scope for removal of filename */ int prefixi, prefixlen = strlen(filenameprefix); for (prefixi = prefixlen; prefixi > 0; prefixi--) if (filenameprefix[prefixi] == '/') { filenameprefix[prefixi] = 0; break; } } buildcommand(command, suffixes[j].command, buf, tmpfilename); xsystem(command); id = fopen(tmpfilename, "r"); if (id) { xfree(buf); return id; } } (*bufend) = 0; } /* if we have a nonzero filename prefix, that is we view a set of * infopages, we don't want to search for a page in all * directories, but only in the prefix directory. Therefore break * here. */ if ((i == -1) &&(filenameprefix)) break; } xfree(buf); return 0; #undef BUF_LEN }