ddf4be898739e96bf71003f4242725fb4882b559
[alioth/jupp.git] / uerror.c
1 /*
2  *      Compiler error handler
3  *      Copyright
4  *              (C) 1992 Joseph H. Allen
5  *
6  *      This file is part of JOE (Joe's Own Editor)
7  */
8 #include "config.h"
9 #include "types.h"
10
11 __RCSID("$MirOS: contrib/code/jupp/uerror.c,v 1.5 2017/12/02 02:07:34 tg Exp $");
12
13 #include "b.h"
14 #include "bw.h"
15 #include "main.h"
16 #include "queue.h"
17 #include "tw.h"
18 #include "ufile.h"
19 #include "utils.h"
20 #include "vs.h"
21 #include "charmap.h"
22 #include "w.h"
23
24 /* Error database */
25
26 typedef struct error ERROR;
27
28 struct error {
29         LINK(ERROR) link;       /* Linked list of errors */
30         long line;              /* Target line number */
31         long org;               /* Original target line number */
32         unsigned char *file;            /* Target file name */
33         long src;               /* Error-file line number */
34         unsigned char *msg;             /* The message */
35 } errors = { { &errors, &errors} };
36 ERROR *errptr = &errors;        /* Current error row */
37
38 B *errbuf = NULL;               /* Buffer with error messages */
39
40 /* Insert and delete notices */
41
42 void inserr(unsigned char *name, long int where, long int n, int bol)
43 {
44         ERROR *e;
45
46         if (name) {
47                 for (e = errors.link.next; e != &errors; e = e->link.next) {
48                         if (!strcmp(e->file, name)) {
49                                 if (e->line > where)
50                                         e->line += n;
51                                 else if (e->line == where && bol)
52                                         e->line += n;
53                         }
54                 }
55         }
56 }
57
58 void delerr(unsigned char *name, long int where, long int n)
59 {
60         ERROR *e;
61
62         if (name) {
63                 for (e = errors.link.next; e != &errors; e = e->link.next) {
64                         if (!strcmp(e->file, name)) {
65                                 if (e->line > where + n)
66                                         e->line -= n;
67                                 else if (e->line > where)
68                                         e->line = where;
69                         }
70                 }
71         }
72 }
73
74 /* Abort notice */
75
76 void abrerr(unsigned char *name)
77 {
78         ERROR *e;
79
80         if (name)
81                 for (e = errors.link.next; e != &errors; e = e->link.next)
82                         if (!strcmp(e->file, name))
83                                 e->line = e->org;
84 }
85
86 /* Save notice */
87
88 void saverr(unsigned char *name)
89 {
90         ERROR *e;
91
92         if (name)
93                 for (e = errors.link.next; e != &errors; e = e->link.next)
94                         if (!strcmp(e->file, name))
95                                 e->org = e->line;
96 }
97
98 /* Pool of free error nodes */
99 ERROR errnodes = { {&errnodes, &errnodes} };
100
101 /* Free an error node */
102
103 static void freeerr(ERROR *n)
104 {
105         vsrm(n->file);
106         vsrm(n->msg);
107         enquef(ERROR, link, &errnodes, n);
108 }
109
110 /* Free all errors */
111
112 static void freeall(void)
113 {
114         while (!qempty(ERROR, link, &errors))
115                 freeerr(deque_f(ERROR, link, errors.link.next));
116         errptr = &errors;
117 }
118
119 /* Parse error messages into database */
120
121 /* From joe's joe 2.9 */
122
123 /* First word on line with a '.' in it.  This is the file name.  The next number after that is the line number. */
124
125 static int parseit(struct charmap *map,unsigned char *s, long int row)
126 {
127         int x, y, flg;
128         unsigned char *name = NULL;
129         long line = -1;
130         ERROR *err;
131
132         y=0;
133         flg=0;
134
135         do {
136                 /* Skip to first word */
137                 for (x = y; s[x] && !(joe_isalnum_(map,s[x]) || s[x] == '.' || s[x] == '/'); ++x) ;
138
139                 /* Skip to end of first word */
140                 for (y = x; joe_isalnum_(map,s[y]) || s[y] == '.' || s[y] == '/'; ++y)
141                         if (s[y] == '.')
142                                 flg = 1;
143         } while (!flg && x!=y);
144
145         /* Save file name */
146         if (x != y)
147                 name = vsncpy(NULL, 0, s + x, y - x);
148
149         /* Skip to first number */
150         for (x = y; s[x] && (s[x] < '0' || s[x] > '9'); ++x) ;
151
152         /* Skip to end of first number */
153         for (y = x; s[y] >= '0' && s[y] <= '9'; ++y) ;
154
155         /* Save line number */
156         if (x != y)
157                 sscanf((char *)(s + x), "%ld", &line);
158         if (line != -1)
159                 --line;
160
161         /* Look for ':' */
162         flg = 0;
163         while (s[y]) {
164                 if (s[y]==':') {
165                         flg = 1;
166                         break;
167                 }
168                 ++y;
169         }
170
171         if (name) {
172                 if (line != -1 && flg) {
173                         /* We have an error */
174                         err = (ERROR *) alitem(&errnodes, sizeof(ERROR));
175                         err->file = name;
176                         err->org = err->line = line;
177                         err->src = row;
178                         err->msg = vsncpy(NULL, 0, sc("\\i"));
179                         err->msg = vsncpy(sv(err->msg), sv(s));
180                         enqueb(ERROR, link, &errors, err);
181                         return 1;
182                 } else
183                         vsrm(name);
184         }
185         return 0;
186 }
187
188 /* Parse the error output contained in a buffer */
189
190 static long parserr(B *b)
191 {
192         P *p = pdup(b->bof);
193         P *q = pdup(p);
194         long nerrs = 0;
195
196         freeall();
197         do {
198                 unsigned char *s;
199
200                 pset(q, p);
201                 p_goto_eol(p);
202                 s = brvs(q, (int) (p->byte - q->byte));
203                 if (s) {
204                         nerrs += parseit(b->o.charmap, s, q->line);
205                         vsrm(s);
206                 }
207         } while (pgetc(p) != NO_MORE_DATA);
208         prm(p);
209         prm(q);
210         return nerrs;
211 }
212
213 BW *find_a_good_bw(B *b)
214 {
215         W *w;
216         BW *bw = 0;
217         /* Find lowest window with buffer */
218         if ((w = maint->topwin) != NULL) {
219                 do {
220                         if ((w->watom->what&TYPETW) && ((BW *)w->object)->b==b && w->y>=0)
221                                 bw = (BW *)w->object;
222                         w = w->link.next;
223                 } while (w != maint->topwin);
224         }
225         if (bw)
226                 return bw;
227         /* Otherwise just find lowest window */
228         if ((w = maint->topwin) != NULL) {
229                 do {
230                         if ((w->watom->what&TYPETW) && w->y>=0)
231                                 bw = (BW *)w->object;
232                         w = w->link.next;
233                 } while (w != maint->topwin);
234         }
235         return bw;
236 }
237
238 int parserrb(B *b)
239 {
240         BW *bw;
241         long n;
242         errbuf = b;
243         freeall();
244         n = parserr(b);
245         bw = find_a_good_bw(b);
246         if (n)
247                 joe_snprintf_1((char *)msgbuf, JOE_MSGBUFSIZE, "%ld messages found", n);
248         else
249                 joe_snprintf_0((char *)msgbuf, JOE_MSGBUFSIZE, "No messages found");
250         msgnw(bw->parent, msgbuf);
251         return 0;
252 }
253
254 int uparserr(BW *bw)
255 {
256         long n;
257         errbuf = bw->b;
258         freeall();
259         n = parserr(bw->b);
260         if (n)
261                 joe_snprintf_1((char *)msgbuf, JOE_MSGBUFSIZE, "%ld messages found", n);
262         else
263                 joe_snprintf_0((char *)msgbuf, JOE_MSGBUFSIZE, "No messages found");
264         msgnw(bw->parent, msgbuf);
265         return 0;
266 }
267
268 int unxterr(BW *bw)
269 {
270         int omid;
271
272         if (errptr->link.next == &errors) {
273                 msgnw(bw->parent, US "No more errors");
274                 return -1;
275         }
276         errptr = errptr->link.next;
277         if (!bw->b->name || strcmp(errptr->file, bw->b->name)) {
278                 if (doswitch(bw, vsdup(errptr->file), NULL, NULL))
279                         return -1;
280                 bw = (BW *) maint->curwin->object;
281         }
282         omid = mid;
283         mid = 1;
284         pline(bw->cursor, errptr->line);
285         setline(errbuf, errptr->src);
286         dofollows();
287         mid = omid;
288         bw->cursor->xcol = piscol(bw->cursor);
289         msgnw(bw->parent, errptr->msg);
290         return 0;
291 }
292
293 int uprverr(BW *bw)
294 {
295         int omid;
296
297         if (errptr->link.prev == &errors) {
298                 msgnw(bw->parent, US "No more errors");
299                 return -1;
300         }
301         errptr = errptr->link.prev;
302         if (!bw->b->name || strcmp(errptr->file, bw->b->name)) {
303                 if (doswitch(bw, vsdup(errptr->file), NULL, NULL))
304                         return -1;
305                 bw = (BW *) maint->curwin->object;
306         }
307         omid = mid;
308         mid = 1;
309         pline(bw->cursor, errptr->line);
310         setline(errbuf, errptr->src);
311         dofollows();
312         mid = omid;
313         bw->cursor->xcol = piscol(bw->cursor);
314         msgnw(bw->parent, errptr->msg);
315         return 0;
316 }