|
|
1.1 root 1: /*************************************************************************
2: * This program is copyright (C) 1985, 1986 by Jonathan Payne. It is *
3: * provided to you without charge for use only on a licensed Unix *
4: * system. You may copy JOVE provided that this notice is included with *
5: * the copy. You may not sell copies of this program or versions *
6: * modified for use on microcomputer systems, unless the copies are *
7: * included with a Unix system distribution and the source is provided. *
8: *************************************************************************/
9:
10: #include "jove.h"
11: #include "io.h"
12: #include "termcap.h"
13:
14: #include <signal.h>
15:
16: private char
17: *errfmt = "^\\{\",\\}\\([^:\"( \t]*\\)\\{\"\\, line ,:,(\\} *\\([0-9][0-9]*\\)[:)]";
18:
19: struct error {
20: Buffer *er_buf; /* Buffer error is in */
21: Line *er_mess, /* Actual error message */
22: *er_text; /* Actual error */
23: int er_char; /* char pos of error */
24: struct error *er_prev, /* List of errors */
25: *er_next;
26: };
27:
28: struct error *cur_error = 0,
29: *errorlist = 0;
30: Buffer *perr_buf = 0; /* Buffer with error messages */
31:
32: int WtOnMk = 1; /* Write the modified files when we make */
33:
34: /* Add an error to the end of the list of errors. This is used for
35: parse-{C,LINT}-errors and for the spell-buffer command */
36:
37: private struct error *
38: AddError(laste, errline, buf, line, charpos)
39: struct error *laste;
40: Line *errline,
41: *line;
42: Buffer *buf;
43: {
44: struct error *new = (struct error *) emalloc(sizeof *new);
45:
46: new->er_prev = laste;
47: if (laste)
48: laste->er_next = new;
49: else {
50: if (errorlist) /* Free up old errors */
51: ErrFree();
52: cur_error = errorlist = new;
53: }
54: laste = new;
55: new->er_next = 0;
56: new->er_buf = buf;
57: new->er_text = line;
58: new->er_char = charpos;
59: new->er_mess = errline;
60:
61: return new;
62: }
63:
64: ParseAll()
65: {
66: ErrParse(errfmt);
67: }
68:
69: XParse()
70: {
71: char *sstr;
72:
73: sstr = ask(errfmt, ProcFmt);
74: ErrParse(sstr);
75: }
76:
77: /* Parse for {C,LINT} errors (or anything that matches fmtstr) in the
78: current buffer. Set up for the next-error command. This is neat
79: because this will work for any kind of output that prints a file
80: name and a line number on the same line. */
81:
82: ErrParse(fmtstr)
83: char *fmtstr;
84: {
85: Bufpos *bp;
86: char fname[FILESIZE],
87: lineno[10],
88: REbuf[128],
89: *REalts[10];
90: int lnum,
91: last_lnum = -1;
92: struct error *ep = 0;
93: Buffer *buf,
94: *lastb = 0;
95: Line *err_line;
96:
97: ErrFree(); /* This is important! */
98: ToFirst();
99: perr_buf = curbuf;
100: REcompile(fmtstr, 1, REbuf, REalts);
101: /* Find a line with a number on it. */
102: while (bp = docompiled(FORWARD, REbuf, REalts)) {
103: SetDot(bp);
104: putmatch(1, fname, sizeof fname);
105: putmatch(2, lineno, sizeof lineno);
106: buf = do_find((Window *) 0, fname, 1);
107: if (buf != lastb) {
108: lastb = buf;
109: last_lnum = -1; /* signals new file */
110: err_line = buf->b_first;
111: }
112: lnum = chr_to_int(lineno, 10, 0);
113: if (lnum == last_lnum) /* one error per line is nicer */
114: continue;
115: if (last_lnum == -1)
116: last_lnum = 1; /* that's where we really are */
117: err_line = next_line(err_line, lnum - last_lnum);
118: ep = AddError(ep, curline, buf, err_line, 0);
119: last_lnum = lnum;
120: }
121: if (cur_error != 0)
122: ShowErr();
123: exp = 1;
124: }
125:
126: /* Free up all the errors */
127:
128: ErrFree()
129: {
130: register struct error *ep;
131:
132: for (ep = errorlist; ep != 0; ep = ep->er_next)
133: free((char *) ep);
134: errorlist = cur_error = 0;
135: }
136:
137: /* Internal next error sets cur_error to the next error, taking the
138: argument count, supplied by the user, into consideration. */
139:
140: private char errbounds[] = "You're at the %s error.",
141: noerrs[] = "No errors!";
142:
143: private
144: toerror(forward)
145: {
146: register int i;
147: register struct error *e = cur_error;
148:
149: if (e == 0)
150: complain(noerrs);
151: if ((forward && (e->er_next == 0)) ||
152: (!forward && (e->er_prev == 0)))
153: complain(errbounds, forward ? "last" : "first");
154:
155: for (i = 0; i < exp; i++) {
156: if ((e = forward ? e->er_next : e->er_prev) == 0)
157: break;
158: cur_error = e;
159: }
160: }
161:
162: NextError()
163: {
164: ToError(1);
165: }
166:
167: PrevError()
168: {
169: ToError(0);
170: }
171:
172: private
173: okay_error()
174: {
175: return ((inlist(perr_buf->b_first, cur_error->er_mess)) &&
176: (inlist(cur_error->er_buf->b_first, cur_error->er_text)));
177: }
178:
179: /* Go the the next error, if there is one. Put the error buffer in
180: one window and the buffer with the error in another window.
181: It checks to make sure that the error actually exists. */
182:
183: ToError(forward)
184: {
185: do {
186: toerror(forward);
187: exp = 1;
188: } while (!okay_error());
189: ShowErr();
190: }
191:
192: int EWSize = 20; /* percentage of screen the error window
193: should be */
194:
195: /* Show the current error, i.e. put the line containing the error message
196: in one window, and the buffer containing the actual error in another
197: window. */
198:
199: ShowErr()
200: {
201: Window *err_wind,
202: *buf_wind;
203: int w_size; /* size of window */
204:
205: if (cur_error == 0)
206: complain(noerrs);
207: if (!okay_error()) {
208: rbell();
209: return;
210: }
211: err_wind = windbp(perr_buf);
212: buf_wind = windbp(cur_error->er_buf);
213:
214: if (err_wind && !buf_wind) {
215: SetWind(err_wind);
216: pop_wind(cur_error->er_buf->b_name, 0, -1);
217: buf_wind = curwind;
218: } else if (!err_wind && buf_wind) {
219: SetWind(buf_wind);
220: pop_wind(perr_buf->b_name, 0, -1);
221: err_wind = curwind;
222: } else if (!err_wind && !buf_wind) {
223: pop_wind(perr_buf->b_name, 0, -1);
224: err_wind = curwind;
225: pop_wind(cur_error->er_buf->b_name, 0, -1);
226: buf_wind = curwind;
227: }
228:
229: /* Put the current error message at the top of its Window */
230: SetWind(err_wind);
231: SetLine(cur_error->er_mess);
232: SetTop(curwind, (curwind->w_line = cur_error->er_mess));
233: w_size = (ILI * EWSize) / 100;
234: if (w_size >= 1)
235: WindSize(curwind, w_size - (curwind->w_height - 1));
236:
237: /* now go to the the line with the error in the other window */
238: SetWind(buf_wind);
239: DotTo(cur_error->er_text, cur_error->er_char);
240: }
241:
242: char ShcomBuf[128] = {0};
243:
244: /* Make a buffer name given the command `command', i.e. "fgrep -n foo *.c"
245: will return the buffer name "fgrep". */
246:
247: char *
248: MakeName(command)
249: char *command;
250: {
251: static char bufname[50];
252: register char *cp = bufname,
253: c;
254:
255: while ((c = *command++) && (c == ' ' || c == '\t'))
256: ;
257: do
258: *cp++ = c;
259: while ((c = *command++) && (c != ' ' && c != '\t'));
260: *cp = 0;
261: strcpy(bufname, basename(bufname));
262:
263: return bufname;
264: }
265:
266: /* Run make, first writing all the modified buffers (if the WtOnMk flag is
267: non-zero), parse the errors, and go the first error. */
268:
269: char make_cmd[128] = "make";
270:
271: MakeErrors()
272: {
273: Window *old = curwind;
274: int status,
275: compilation;
276:
277: if (WtOnMk)
278: put_bufs(0);
279: /* When we're not doing make or cc (i.e., the last command
280: was probably a grep or something) and the user just types
281: C-X C-E, he probably (possibly, hopefully, usually (in my
282: case)) doesn't want to do the grep again but rather wants
283: to do a make again; so we ring the bell and insert the
284: default command and let the person decide. */
285:
286: compilation = (sindex("make", make_cmd) || sindex("cc", make_cmd));
287: if (exp_p || !compilation) {
288: if (!compilation) {
289: rbell();
290: Inputp = make_cmd; /* insert the default for the
291: user */
292: }
293: null_ncpy(make_cmd, ask(make_cmd, "Compilation command: "),
294: sizeof (make_cmd) - 1);
295: }
296: status = UnixToBuf(MakeName(make_cmd), YES, EWSize, YES, Shell, basename(Shell), ShFlags, make_cmd, 0);
297: com_finish(status, make_cmd);
298:
299: ErrParse(errfmt);
300:
301: if (!cur_error)
302: SetWind(old);
303: }
304:
305: #ifdef SPELL
306:
307: SpelBuffer()
308: {
309: char *Spell = "Spell",
310: com[100];
311: Window *savewp = curwind;
312:
313: put_bufs(0);
314: sprintf(com, "spell %s", curbuf->b_fname);
315: (void) UnixToBuf(Spell, YES, EWSize, YES, Shell, basename(Shell), ShFlags, com, 0);
316: message("[Delete the irrelevant words and then type C-X C-C]");
317: Recur();
318: SetWind(savewp);
319: SpelParse(Spell);
320: }
321:
322: SpelWords()
323: {
324: char *buftospel;
325: Buffer *wordsb = curbuf;
326:
327: if ((buftospel = ask_buf((Buffer *) 0)) == 0)
328: return;
329: SetBuf(do_select(curwind, buftospel));
330: SpelParse(wordsb->b_name);
331: }
332:
333: SpelParse(bname)
334: char *bname;
335: {
336: Buffer *buftospel,
337: *wordsb;
338: char wordspel[100];
339: Bufpos *bp;
340: struct error *ep = 0;
341:
342: ErrFree(); /* This is important! */
343:
344: buftospel = curbuf;
345: wordsb = buf_exists(bname);
346: perr_buf = wordsb; /* This is important (buffer containing
347: error messages) */
348: SetBuf(wordsb);
349: ToFirst();
350: f_mess("Finding misspelled words ... ");
351: while (!lastp(curline)) {
352: sprintf(wordspel, "\\<%s\\>", linebuf);
353: SetBuf(buftospel);
354: ToFirst();
355: while (bp = dosearch(wordspel, 1, 1)) {
356: SetDot(bp);
357: ep = AddError(ep, wordsb->b_dot, buftospel,
358: curline, curchar);
359: }
360: SetBuf(wordsb);
361: line_move(FORWARD, NO);
362: }
363: add_mess("Done.");
364: SetBuf(buftospel);
365: ShowErr();
366: }
367:
368: #endif SPELL
369:
370: ShToBuf()
371: {
372: char bufname[100];
373:
374: strcpy(bufname, ask((char *) 0, "Buffer: "));
375: DoShell(bufname, ask(ShcomBuf, "Command: "));
376: }
377:
378: ShellCom()
379: {
380: null_ncpy(ShcomBuf, ask(ShcomBuf, ProcFmt), (sizeof ShcomBuf) - 1);
381: DoShell(MakeName(ShcomBuf), ShcomBuf);
382: }
383:
384: /* Run the shell command into `bufname'. Empty the buffer except when we
385: give a numeric argument, in which case it inserts the output at the
386: current position in the buffer. */
387:
388: private
389: DoShell(bufname, command)
390: char *bufname,
391: *command;
392: {
393: Window *savewp = curwind;
394: int status;
395:
396: exp = 1;
397: status = UnixToBuf(bufname, YES, 0, !exp_p, Shell, basename(Shell),
398: ShFlags, command, 0);
399: com_finish(status, command);
400: SetWind(savewp);
401: }
402:
403: private
404: com_finish(status, com)
405: char *com;
406: {
407: s_mess("\"%s\" completed %ssuccessfully.", com, status ? "un" : NullStr);
408: }
409:
410: dowait(pid, status)
411: int pid,
412: *status;
413: {
414: #ifndef IPROCS
415:
416: int rpid;
417:
418: while ((rpid = wait(status)) != pid)
419: ;
420: #else
421:
422: #ifdef BSD4_2
423: # include <sys/wait.h>
424: #else
425: # include <wait.h>
426: #endif
427:
428: union wait w;
429: int rpid;
430:
431: for (;;) {
432: #ifndef VMUNIX
433: rpid = wait2(&w.w_status, 0);
434: #else
435: rpid = wait3(&w, 0, (struct rusage *) 0);
436: #endif
437: if (rpid == pid) {
438: if (status)
439: *status = w.w_status;
440: break;
441: } else
442: kill_off(rpid, w);
443: }
444: #endif IPROCS
445: }
446:
447: /* Run the command to bufname, erase the buffer if clobber is non-zero,
448: and redisplay if disp is non-zero. Leaves current buffer in `bufname'
449: and leaves any windows it creates lying around. It's up to the caller
450: to fix everything up after we're done. (Usually there's nothing to
451: fix up.) */
452:
453: /* VARARGS3 */
454:
455: UnixToBuf(bufname, disp, wsize, clobber, cmd, args)
456: char *bufname,
457: *cmd;
458: {
459: int p[2],
460: pid;
461: extern int ninbuf;
462: Buffer *bp;
463:
464: if (clobber && (bp = buf_exists(bufname)) != 0 &&
465: bp->b_type != B_PROCESS && bp->b_type != B_IPROCESS)
466: complain("Command would over-write buffer %s.", bufname);
467: if (disp) {
468: message("Starting up...");
469: pop_wind(bufname, clobber, clobber ? B_PROCESS : B_FILE);
470: wsize = (LI * wsize) / 100;
471: if (wsize >= 1 && !one_windp())
472: WindSize(curwind, wsize - (curwind->w_height - 1));
473: redisplay();
474: }
475: exp = 1;
476: dopipe(p);
477: pid = fork();
478: if (pid == -1) {
479: pclose(p);
480: complain("[Fork failed]");
481: }
482: if (pid == 0) {
483: (void) close(0);
484: (void) open("/dev/null", 0);
485: (void) close(1);
486: (void) close(2);
487: (void) dup(p[1]);
488: (void) dup(p[1]);
489: pclose(p);
490: execv(cmd, (char **) &args);
491: (void) write(1, "Execl failed.\n", 14);
492: _exit(1);
493: } else {
494: int status;
495: int (*oldint)() = signal(SIGINT, SIG_IGN);
496: char *mess;
497: File *fp;
498:
499: #ifdef IPROCS
500: sighold(SIGCHLD);
501: #endif
502:
503: (void) close(p[1]);
504: fp = fd_open(cmd, F_READ, p[0], iobuff, LBSIZE);
505: while (inIOread = 1, f_gets(fp, genbuf, LBSIZE) != EOF) {
506: inIOread = 0;
507: ins_str(genbuf, YES);
508: LineInsert();
509: if (disp != 0 && fp->f_cnt <= 0) {
510: #ifdef LOAD_AV
511: {
512: double theavg;
513:
514: get_la(&theavg);
515: if (theavg < 2.0)
516: mess = "Screaming along...";
517: else if (theavg < 5.0)
518: mess = "Chugging along...";
519: else
520: mess = "Crawling along...";
521: }
522: #else
523: mess = "Chugging along...";
524: #endif LOAD_AV
525: message(mess);
526: redisplay();
527: }
528: }
529: if (disp)
530: DrawMesg(NO);
531: close_file(fp);
532: (void) signal(SIGINT, oldint);
533: dowait(pid, &status);
534: #ifdef IPROCS
535: sigrelse(SIGCHLD);
536: #endif
537: return status;
538: }
539: return 0;
540: }
541:
542: #ifdef BSD4_2
543:
544: private int SigMask = 0;
545:
546: sighold(sig)
547: {
548: (void) sigblock(SigMask |= (1 << (sig - 1)));
549: }
550:
551: sigrelse(sig)
552: {
553: (void) sigsetmask(SigMask &= ~(1 << (sig - 1)));
554: }
555:
556: #endif
557:
558: FilterRegion()
559: {
560: char *cmd = ask((char *) 0, ": %f (through command) ", ProcFmt);
561:
562: RegToUnix(curbuf, cmd);
563: }
564:
565: /* Send the current region to CMD and insert the output from the
566: command into OUT_BUF. */
567:
568: RegToUnix(outbuf, cmd)
569: Buffer *outbuf;
570: char *cmd;
571: {
572: Mark *m = CurMark();
573: char *tname = mktemp("/tmp/jfilterXXXXXX"),
574: combuf[130];
575: Window *save_wind = curwind;
576: int status;
577: File *fp;
578:
579: CATCH
580: fp = open_file(tname, iobuff, F_WRITE, COMPLAIN, QUIET);
581: putreg(fp, m->m_line, m->m_char, curline, curchar, YES);
582: DelReg();
583: sprintf(combuf, "%s < %s", cmd, tname);
584: status = UnixToBuf(outbuf->b_name, NO, 0, outbuf->b_type == B_SCRATCH,
585: Shell, basename(Shell), ShFlags, combuf, 0);
586: ONERROR
587: ; /* Do nothing ... but fall through and delete the tmp
588: file. */
589: ENDCATCH
590: f_close(fp);
591: (void) unlink(tname);
592: SetWind(save_wind);
593: com_finish(status, combuf);
594: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.