xref: /plan9-contrib/sys/src/cmd/split.c (revision 4d44ba9b9ee4246ddbd96c7fcaf0918ab92ab35a)
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
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 		if(!(exp = regcomp(iflag? fold(pattern,strlen(pattern)): pattern)))
74bd389b36SDavid du Colombier 			badexp();
75bd389b36SDavid du Colombier 		while((line=Brdline(b,'\n')) != 0) {
76bd389b36SDavid du Colombier 			Resub match[2];
7780ee5cbfSDavid du Colombier 			memset(match, 0, sizeof match);
787dd7cddfSDavid du Colombier 			line[Blinelen(b)-1] = 0;
797dd7cddfSDavid du Colombier 			if(regexec(exp,iflag?fold(line,Blinelen(b)-1):line,match,2)) {
80bd389b36SDavid du Colombier 				if(matchfile(match) && xflag)
81bd389b36SDavid du Colombier 					continue;
82bd389b36SDavid du Colombier 			} else if(output == 0)
83bd389b36SDavid du Colombier 				nextfile();	/* at most once */
847dd7cddfSDavid du Colombier 			Bwrite(output, line, Blinelen(b)-1);
85bd389b36SDavid du Colombier 			Bputc(output, '\n');
86bd389b36SDavid du Colombier 		}
87bd389b36SDavid du Colombier 	} else {
887dd7cddfSDavid du Colombier 		int linecnt = n;
897dd7cddfSDavid du Colombier 
90bd389b36SDavid du Colombier 		while((line=Brdline(b,'\n')) != 0) {
91bd389b36SDavid du Colombier 			if(++linecnt > n) {
92bd389b36SDavid du Colombier 				nextfile();
93bd389b36SDavid du Colombier 				linecnt = 1;
94bd389b36SDavid du Colombier 			}
957dd7cddfSDavid du Colombier 			Bwrite(output, line, Blinelen(b));
96bd389b36SDavid du Colombier 		}
97219b2ee8SDavid du Colombier 
98219b2ee8SDavid du Colombier 		/*
99219b2ee8SDavid du Colombier 		 * in case we didn't end with a newline, tack whatever's
100219b2ee8SDavid du Colombier 		 * left onto the last file
101219b2ee8SDavid du Colombier 		 */
102219b2ee8SDavid du Colombier 		while((n = Bread(b, buf, sizeof(buf))) > 0)
103219b2ee8SDavid du Colombier 			Bwrite(output, buf, n);
104bd389b36SDavid du Colombier 	}
1057dd7cddfSDavid du Colombier 	if(b != nil)
106219b2ee8SDavid du Colombier 		Bterm(b);
107bd389b36SDavid du Colombier 	exits(0);
108bd389b36SDavid du Colombier }
109bd389b36SDavid du Colombier 
110bd389b36SDavid du Colombier int
111bd389b36SDavid du Colombier nextfile(void)
112bd389b36SDavid du Colombier {
113bd389b36SDavid du Colombier 	static canopen = 1;
114bd389b36SDavid du Colombier 	if(suff[0] > 'z') {
115bd389b36SDavid du Colombier 		if(canopen)
116bd389b36SDavid du Colombier 			fprint(2, "split: file %szz not split\n",stem);
117bd389b36SDavid du Colombier 		canopen = 0;
118bd389b36SDavid du Colombier 	} else {
119*4d44ba9bSDavid du Colombier 		snprint(name, sizeof name, "%s%s", stem, suff);
120bd389b36SDavid du Colombier 		if(++suff[1] > 'z')
121bd389b36SDavid du Colombier 			suff[1] = 'a', ++suff[0];
122bd389b36SDavid du Colombier 		openf();
123bd389b36SDavid du Colombier 	}
124bd389b36SDavid du Colombier 	return canopen;
125bd389b36SDavid du Colombier }
126bd389b36SDavid du Colombier 
127bd389b36SDavid du Colombier int
128bd389b36SDavid du Colombier matchfile(Resub *match)
129bd389b36SDavid du Colombier {
130bd389b36SDavid du Colombier 	if(match[1].sp) {
131bd389b36SDavid du Colombier 		int len = match[1].ep - match[1].sp;
132bd389b36SDavid du Colombier 		strncpy(name, match[1].sp, len);
133bd389b36SDavid du Colombier 		strcpy(name+len, suffix);
134bd389b36SDavid du Colombier 		openf();
135bd389b36SDavid du Colombier 		return 1;
136bd389b36SDavid du Colombier 	}
137bd389b36SDavid du Colombier 	return nextfile();
138bd389b36SDavid du Colombier }
139bd389b36SDavid du Colombier 
140bd389b36SDavid du Colombier void
141bd389b36SDavid du Colombier openf(void)
142bd389b36SDavid du Colombier {
14380ee5cbfSDavid du Colombier 	static int fd = 0;
144bd389b36SDavid du Colombier 	Bflush(output);
145219b2ee8SDavid du Colombier 	Bterm(output);
14680ee5cbfSDavid du Colombier 	if(fd > 0)
14780ee5cbfSDavid du Colombier 		close(fd);
1487dd7cddfSDavid du Colombier 	fd = create(name,OWRITE,0666);
1497dd7cddfSDavid du Colombier 	if(fd < 0) {
1507dd7cddfSDavid du Colombier 		fprint(2, "grep: can't create %s: %r\n", name);
1517dd7cddfSDavid du Colombier 		exits("create");
152bd389b36SDavid du Colombier 	}
153bd389b36SDavid du Colombier 	Binit(output, fd, OWRITE);
154bd389b36SDavid du Colombier }
155bd389b36SDavid du Colombier 
156bd389b36SDavid du Colombier char *
157bd389b36SDavid du Colombier fold(char *s, int n)
158bd389b36SDavid du Colombier {
159bd389b36SDavid du Colombier 	static char *fline;
160bd389b36SDavid du Colombier 	static int linesize = 0;
161bd389b36SDavid du Colombier 	char *t;
1627dd7cddfSDavid du Colombier 
163bd389b36SDavid du Colombier 	if(linesize < n+1){
164bd389b36SDavid du Colombier 		fline = realloc(fline,n+1);
165bd389b36SDavid du Colombier 		linesize = n+1;
166bd389b36SDavid du Colombier 	}
167bd389b36SDavid du Colombier 	for(t=fline; *t++ = tolower(*s++); )
168bd389b36SDavid du Colombier 		continue;
169bd389b36SDavid du Colombier 		/* we assume the 'A'-'Z' only appear as themselves
170bd389b36SDavid du Colombier 		 * in a utf encoding.
171bd389b36SDavid du Colombier 		 */
172bd389b36SDavid du Colombier 	return fline;
173bd389b36SDavid du Colombier }
174bd389b36SDavid du Colombier 
175bd389b36SDavid du Colombier void
176bd389b36SDavid du Colombier usage(void)
177bd389b36SDavid du Colombier {
178bd389b36SDavid du Colombier 	fprint(2, "usage: split [-n num] [-e exp] [-f stem] [-s suff] [-x] [-i] [file]\n");
1797dd7cddfSDavid du Colombier 	exits("usage");
180bd389b36SDavid du Colombier }
181bd389b36SDavid du Colombier 
182bd389b36SDavid du Colombier void
183bd389b36SDavid du Colombier badexp(void)
184bd389b36SDavid du Colombier {
185bd389b36SDavid du Colombier 	fprint(2, "split: bad regular expression\n");
186bd389b36SDavid du Colombier 	exits("bad regular expression");
187bd389b36SDavid du Colombier }
188