1bd389b36SDavid du Colombier #include <u.h>
2bd389b36SDavid du Colombier #include <libc.h>
3bd389b36SDavid du Colombier #include <bio.h>
4bd389b36SDavid du Colombier #include <regexp.h>
5bd389b36SDavid du Colombier
6bd389b36SDavid du Colombier char digit[] = "0123456789";
7bd389b36SDavid du Colombier char *suffix = "";
8bd389b36SDavid du Colombier char *stem = "x";
9bd389b36SDavid du Colombier char suff[] = "aa";
10bd389b36SDavid du Colombier char name[200];
11bd389b36SDavid du Colombier Biobuf bout;
12bd389b36SDavid du Colombier Biobuf *output = &bout;
13bd389b36SDavid du Colombier
14bd389b36SDavid du Colombier extern int nextfile(void);
15bd389b36SDavid du Colombier extern int matchfile(Resub*);
16bd389b36SDavid du Colombier extern void openf(void);
17bd389b36SDavid du Colombier extern char *fold(char*,int);
18bd389b36SDavid du Colombier extern void usage(void);
19bd389b36SDavid du Colombier extern void badexp(void);
20bd389b36SDavid du Colombier
21bd389b36SDavid du Colombier void
main(int argc,char * argv[])22bd389b36SDavid du Colombier main(int argc, char *argv[])
23bd389b36SDavid du Colombier {
24bd389b36SDavid du Colombier Reprog *exp;
25bd389b36SDavid du Colombier char *pattern = 0;
267dd7cddfSDavid du Colombier int n = 1000;
27bd389b36SDavid du Colombier char *line;
28bd389b36SDavid du Colombier int xflag = 0;
29bd389b36SDavid du Colombier int iflag = 0;
30bd389b36SDavid du Colombier Biobuf bin;
31bd389b36SDavid du Colombier Biobuf *b = &bin;
32219b2ee8SDavid du Colombier char buf[256];
33bd389b36SDavid du Colombier
34bd389b36SDavid du Colombier ARGBEGIN {
35d9306527SDavid du Colombier case 'l':
36bd389b36SDavid du Colombier case 'n':
3759cc4ca5SDavid du Colombier n=atoi(EARGF(usage()));
38bd389b36SDavid du Colombier break;
39bd389b36SDavid du Colombier case 'e':
4059cc4ca5SDavid du Colombier pattern = strdup(EARGF(usage()));
41bd389b36SDavid du Colombier break;
42bd389b36SDavid du Colombier case 'f':
4359cc4ca5SDavid du Colombier stem = strdup(EARGF(usage()));
44bd389b36SDavid du Colombier break;
45bd389b36SDavid du Colombier case 's':
4659cc4ca5SDavid du Colombier suffix = strdup(EARGF(usage()));
47bd389b36SDavid du Colombier break;
48bd389b36SDavid du Colombier case 'x':
49bd389b36SDavid du Colombier xflag++;
50bd389b36SDavid du Colombier break;
51bd389b36SDavid du Colombier case 'i':
52bd389b36SDavid du Colombier iflag++;
53bd389b36SDavid du Colombier break;
54bd389b36SDavid du Colombier default:
557dd7cddfSDavid du Colombier usage();
567dd7cddfSDavid du Colombier break;
57bd389b36SDavid du Colombier
587dd7cddfSDavid du Colombier } ARGEND;
597dd7cddfSDavid du Colombier
607dd7cddfSDavid du Colombier if(argc < 0 || argc > 1)
617dd7cddfSDavid du Colombier usage();
627dd7cddfSDavid du Colombier
637dd7cddfSDavid du Colombier if(argc != 0) {
64bd389b36SDavid du Colombier b = Bopen(argv[0], OREAD);
657dd7cddfSDavid du Colombier if(b == nil) {
66bd389b36SDavid du Colombier fprint(2, "split: can't open %s: %r\n", argv[0]);
677dd7cddfSDavid du Colombier exits("open");
68bd389b36SDavid du Colombier }
697dd7cddfSDavid du Colombier } else
707dd7cddfSDavid du Colombier Binit(b, 0, OREAD);
717dd7cddfSDavid du Colombier
72bd389b36SDavid du Colombier if(pattern) {
73bd389b36SDavid du Colombier Resub match[2];
74*25fc6993SDavid du Colombier
75*25fc6993SDavid du Colombier if(!(exp = regcomp(iflag? fold(pattern, strlen(pattern)):
76*25fc6993SDavid du Colombier pattern)))
77*25fc6993SDavid du Colombier badexp();
78*25fc6993SDavid du Colombier memset(match, 0, sizeof match);
79*25fc6993SDavid du Colombier matchfile(match);
80*25fc6993SDavid du Colombier while((line=Brdline(b,'\n')) != 0) {
8180ee5cbfSDavid du Colombier memset(match, 0, sizeof match);
827dd7cddfSDavid du Colombier line[Blinelen(b)-1] = 0;
83*25fc6993SDavid du Colombier if(regexec(exp, iflag? fold(line, Blinelen(b)-1): line,
84*25fc6993SDavid du Colombier match, 2)) {
85bd389b36SDavid du Colombier if(matchfile(match) && xflag)
86bd389b36SDavid du Colombier continue;
87bd389b36SDavid du Colombier } else if(output == 0)
88bd389b36SDavid du Colombier nextfile(); /* at most once */
897dd7cddfSDavid du Colombier Bwrite(output, line, Blinelen(b)-1);
90bd389b36SDavid du Colombier Bputc(output, '\n');
91bd389b36SDavid du Colombier }
92bd389b36SDavid du Colombier } else {
937dd7cddfSDavid du Colombier int linecnt = n;
947dd7cddfSDavid du Colombier
95bd389b36SDavid du Colombier while((line=Brdline(b,'\n')) != 0) {
96bd389b36SDavid du Colombier if(++linecnt > n) {
97bd389b36SDavid du Colombier nextfile();
98bd389b36SDavid du Colombier linecnt = 1;
99bd389b36SDavid du Colombier }
1007dd7cddfSDavid du Colombier Bwrite(output, line, Blinelen(b));
101bd389b36SDavid du Colombier }
102219b2ee8SDavid du Colombier
103219b2ee8SDavid du Colombier /*
104219b2ee8SDavid du Colombier * in case we didn't end with a newline, tack whatever's
105219b2ee8SDavid du Colombier * left onto the last file
106219b2ee8SDavid du Colombier */
107219b2ee8SDavid du Colombier while((n = Bread(b, buf, sizeof(buf))) > 0)
108219b2ee8SDavid du Colombier Bwrite(output, buf, n);
109bd389b36SDavid du Colombier }
1107dd7cddfSDavid du Colombier if(b != nil)
111219b2ee8SDavid du Colombier Bterm(b);
112bd389b36SDavid du Colombier exits(0);
113bd389b36SDavid du Colombier }
114bd389b36SDavid du Colombier
115bd389b36SDavid du Colombier int
nextfile(void)116bd389b36SDavid du Colombier nextfile(void)
117bd389b36SDavid du Colombier {
118*25fc6993SDavid du Colombier static int canopen = 1;
119*25fc6993SDavid du Colombier
120bd389b36SDavid du Colombier if(suff[0] > 'z') {
121bd389b36SDavid du Colombier if(canopen)
122bd389b36SDavid du Colombier fprint(2, "split: file %szz not split\n",stem);
123bd389b36SDavid du Colombier canopen = 0;
124bd389b36SDavid du Colombier } else {
1254d44ba9bSDavid du Colombier snprint(name, sizeof name, "%s%s", stem, suff);
126bd389b36SDavid du Colombier if(++suff[1] > 'z')
127bd389b36SDavid du Colombier suff[1] = 'a', ++suff[0];
128bd389b36SDavid du Colombier openf();
129bd389b36SDavid du Colombier }
130bd389b36SDavid du Colombier return canopen;
131bd389b36SDavid du Colombier }
132bd389b36SDavid du Colombier
133bd389b36SDavid du Colombier int
matchfile(Resub * match)134bd389b36SDavid du Colombier matchfile(Resub *match)
135bd389b36SDavid du Colombier {
136bd389b36SDavid du Colombier if(match[1].sp) {
137bd389b36SDavid du Colombier int len = match[1].ep - match[1].sp;
138*25fc6993SDavid du Colombier
139bd389b36SDavid du Colombier strncpy(name, match[1].sp, len);
140bd389b36SDavid du Colombier strcpy(name+len, suffix);
141bd389b36SDavid du Colombier openf();
142bd389b36SDavid du Colombier return 1;
143bd389b36SDavid du Colombier }
144bd389b36SDavid du Colombier return nextfile();
145bd389b36SDavid du Colombier }
146bd389b36SDavid du Colombier
147bd389b36SDavid du Colombier void
openf(void)148bd389b36SDavid du Colombier openf(void)
149bd389b36SDavid du Colombier {
15080ee5cbfSDavid du Colombier static int fd = 0;
151*25fc6993SDavid du Colombier
152bd389b36SDavid du Colombier Bflush(output);
153219b2ee8SDavid du Colombier Bterm(output);
15480ee5cbfSDavid du Colombier if(fd > 0)
15580ee5cbfSDavid du Colombier close(fd);
1567dd7cddfSDavid du Colombier fd = create(name,OWRITE,0666);
1577dd7cddfSDavid du Colombier if(fd < 0) {
1587dd7cddfSDavid du Colombier fprint(2, "grep: can't create %s: %r\n", name);
1597dd7cddfSDavid du Colombier exits("create");
160bd389b36SDavid du Colombier }
161bd389b36SDavid du Colombier Binit(output, fd, OWRITE);
162bd389b36SDavid du Colombier }
163bd389b36SDavid du Colombier
164bd389b36SDavid du Colombier char *
fold(char * s,int n)165bd389b36SDavid du Colombier fold(char *s, int n)
166bd389b36SDavid du Colombier {
167bd389b36SDavid du Colombier static char *fline;
168bd389b36SDavid du Colombier static int linesize = 0;
169bd389b36SDavid du Colombier char *t;
1707dd7cddfSDavid du Colombier
171bd389b36SDavid du Colombier if(linesize < n+1){
172bd389b36SDavid du Colombier fline = realloc(fline,n+1);
173bd389b36SDavid du Colombier linesize = n+1;
174bd389b36SDavid du Colombier }
175bd389b36SDavid du Colombier for(t=fline; *t++ = tolower(*s++); )
176bd389b36SDavid du Colombier continue;
177bd389b36SDavid du Colombier /* we assume the 'A'-'Z' only appear as themselves
178bd389b36SDavid du Colombier * in a utf encoding.
179bd389b36SDavid du Colombier */
180bd389b36SDavid du Colombier return fline;
181bd389b36SDavid du Colombier }
182bd389b36SDavid du Colombier
183bd389b36SDavid du Colombier void
usage(void)184bd389b36SDavid du Colombier usage(void)
185bd389b36SDavid du Colombier {
186bd389b36SDavid du Colombier fprint(2, "usage: split [-n num] [-e exp] [-f stem] [-s suff] [-x] [-i] [file]\n");
1877dd7cddfSDavid du Colombier exits("usage");
188bd389b36SDavid du Colombier }
189bd389b36SDavid du Colombier
190bd389b36SDavid du Colombier void
badexp(void)191bd389b36SDavid du Colombier badexp(void)
192bd389b36SDavid du Colombier {
193bd389b36SDavid du Colombier fprint(2, "split: bad regular expression\n");
194bd389b36SDavid du Colombier exits("bad regular expression");
195bd389b36SDavid du Colombier }
196