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