xref: /openbsd-src/usr.bin/mg/grep.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpenBSD: grep.c,v 1.8 2003/04/08 21:19:57 vincent Exp $	*/
2 /*
3  * Copyright (c) 2001 Artur Grabowski <art@openbsd.org>.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "def.h"
27 #include "kbd.h"
28 #include "funmap.h"
29 
30 static int	compile_goto_error(int f, int n);
31 static int	next_error(int f, int n);
32 static int	grep(int, int);
33 static int	compile(int, int);
34 static int	gid(int, int);
35 static BUFFER	*compile_mode(char *name, char *command);
36 
37 
38 void grep_init(void);
39 
40 static char compile_last_command[NFILEN] = "make ";
41 
42 /*
43  * Hints for next-error
44  *
45  * XXX - need some kind of callback to find out when those get killed.
46  */
47 MGWIN *compile_win;
48 BUFFER *compile_buffer;
49 
50 static PF compile_pf[] = {
51 	compile_goto_error,
52 };
53 
54 static struct KEYMAPE (1 + IMAPEXT) compilemap = {
55 	1,
56 	1 + IMAPEXT,
57 	rescan,
58 	{
59 		{ CCHR('M'), CCHR('M'), compile_pf, NULL },
60 	}
61 };
62 
63 void
64 grep_init(void)
65 {
66 	funmap_add(compile_goto_error, "compile-goto-error");
67 	funmap_add(next_error, "next-error");
68 	funmap_add(grep, "grep");
69 	funmap_add(compile, "compile");
70 	funmap_add(gid, "gid");
71 	maps_add((KEYMAP *)&compilemap, "compile");
72 }
73 
74 static int
75 grep(int f, int n)
76 {
77 	char command[NFILEN + 20];
78 	char prompt[NFILEN];
79 	BUFFER *bp;
80 	MGWIN *wp;
81 
82 	(void)strlcpy(prompt, "grep -n ", sizeof prompt);
83 	if (eread("Run grep: ", prompt, NFILEN, EFDEF|EFNEW|EFCR) == ABORT)
84 		return ABORT;
85 
86 	(void)snprintf(command, sizeof command, "%s /dev/null", prompt);
87 
88 	if ((bp = compile_mode("*grep*", command)) == NULL)
89 		return FALSE;
90 	if ((wp = popbuf(bp)) == NULL)
91 		return FALSE;
92 	curbp = bp;
93 	compile_win = curwp = wp;
94 	return TRUE;
95 }
96 
97 static int
98 compile(int f, int n)
99 {
100 	char command[NFILEN + 20];
101 	char prompt[NFILEN];
102 	BUFFER *bp;
103 	MGWIN *wp;
104 
105 	(void)strlcpy(prompt, compile_last_command, sizeof prompt);
106 	if (eread("Compile command: ", prompt, NFILEN, EFDEF|EFNEW|EFCR) == ABORT)
107 		return ABORT;
108 	(void)strlcpy(compile_last_command, prompt, sizeof compile_last_command);
109 
110 	(void)snprintf(command, sizeof command, "%s 2>&1", prompt);
111 
112 	if ((bp = compile_mode("*compile*", command)) == NULL)
113 		return FALSE;
114 	if ((wp = popbuf(bp)) == NULL)
115 		return FALSE;
116 	curbp = bp;
117 	compile_win = curwp = wp;
118 	return TRUE;
119 }
120 
121 /* id-utils foo. */
122 static int
123 gid(int f, int n)
124 {
125 	char command[NFILEN + 20];
126 	char prompt[NFILEN];
127 	BUFFER *bp;
128 	MGWIN *wp;
129 
130 	if (eread("Run gid (with args): ", prompt, NFILEN, EFNEW|EFCR) == ABORT)
131 		return ABORT;
132 
133 	(void)snprintf(command, sizeof command, "gid %s", prompt);
134 
135 	if ((bp = compile_mode("*gid*", command)) == NULL)
136 		return FALSE;
137 	if ((wp = popbuf(bp)) == NULL)
138 		return FALSE;
139 	curbp = bp;
140 	compile_win = curwp = wp;
141 	return TRUE;
142 }
143 
144 BUFFER *
145 compile_mode(char *name, char *command)
146 {
147 	BUFFER *bp;
148 	FILE *pipe;
149 	char *buf;
150 	size_t len;
151 	int ret;
152 
153 	bp = bfind(name, TRUE);
154 	if (bclear(bp) != TRUE)
155 		return NULL;
156 
157 	addlinef(bp, "Running (%s).", command);
158 	addline(bp, "");
159 
160 	if ((pipe = popen(command, "r")) == NULL) {
161 		ewprintf("Problem opening pipe");
162 		return NULL;
163 	}
164 	/*
165 	 * We know that our commands are nice and the last line will end with
166 	 * a \n, so we don't need to try to deal with the last line problem
167 	 * in fgetln.
168 	 */
169 	while ((buf = fgetln(pipe, &len)) != NULL) {
170 		buf[len - 1] = '\0';
171 		addline(bp, buf);
172 	}
173 	ret = pclose(pipe);
174 	addline(bp, "");
175 	addlinef(bp, "Command (%s) completed %s.", command,
176 		ret == 0 ? "successfully" : "with errors");
177 	bp->b_dotp = lforw(bp->b_linep);	/* go to first line */
178 	bp->b_modes[0] = name_mode("fundamental");
179 	bp->b_modes[1] = name_mode("compile");
180 	bp->b_nmodes = 1;
181 
182 	compile_buffer = bp;
183 
184 	return bp;
185 }
186 
187 static int
188 compile_goto_error(int f, int n)
189 {
190 	BUFFER *bp;
191 	MGWIN *wp;
192 	char *fname, *line, *lp, *ln, *lp1;
193 	int lineno, len;
194 	char *adjf;
195 
196 	compile_win = curwp;
197 	compile_buffer = curbp;
198 
199 retry:
200 	len = llength(curwp->w_dotp);
201 
202 	if ((line = malloc(len + 1)) == NULL)
203 		return FALSE;
204 
205 	(void)memcpy(line, curwp->w_dotp->l_text, len);
206 	line[len] = '\0';
207 
208 	lp = line;
209 	if ((fname = strsep(&lp, ":")) == NULL)
210 		goto fail;
211 	if ((ln = strsep(&lp, ":")) == NULL)
212 		goto fail;
213 	lineno = strtol(ln, &lp1, 10);
214 	if (lp != lp1 + 1)
215 		goto fail;
216 	free(line);
217 
218 	adjf = adjustname(fname);
219 	if (adjf == NULL)
220 		return (FALSE);
221 	if ((bp = findbuffer(adjf)) == NULL)
222 		return FALSE;
223 	if ((wp = popbuf(bp)) == NULL)
224 		return FALSE;
225 	curbp = bp;
226 	curwp = wp;
227 	if (bp->b_fname[0] == 0)
228 		readin(adjf);
229 	gotoline(FFARG, lineno);
230 	return TRUE;
231 fail:
232 	free(line);
233 	if (curwp->w_dotp != lback(curbp->b_linep)) {
234 		curwp->w_dotp = lforw(curwp->w_dotp);
235 		curwp->w_flag |= WFMOVE;
236 		goto retry;
237 	}
238 	ewprintf("No more hits");
239 	return FALSE;
240 }
241 
242 static int
243 next_error(int f, int n)
244 {
245 	if (compile_win == NULL || compile_buffer == NULL) {
246 		ewprintf("No compilation active");
247 		return FALSE;
248 	}
249 	curwp = compile_win;
250 	curbp = compile_buffer;
251 	if (curwp->w_dotp == lback(curbp->b_linep)) {
252 		ewprintf("No more hits");
253 		return FALSE;
254 	}
255 	curwp->w_dotp = lforw(curwp->w_dotp);
256 	curwp->w_flag |= WFMOVE;
257 
258 	return compile_goto_error(f, n);
259 }
260