1 /* The following Lucent copyright notice applies to report_where()
2 and the original introuble* routines (moved here in 2011 from
3 rops.c and rops2.c). */
4
5 /****************************************************************
6 Copyright (C) 1997 Lucent Technologies
7 All Rights Reserved
8
9 Permission to use, copy, modify, and distribute this software and
10 its documentation for any purpose and without fee is hereby
11 granted, provided that the above copyright notice appear in all
12 copies and that both that the copyright notice and this
13 permission notice and warranty disclaimer appear in supporting
14 documentation, and that the name of Lucent or any of its entities
15 not be used in advertising or publicity pertaining to
16 distribution of the software without specific, written prior
17 permission.
18
19 LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
20 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
21 IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
22 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
23 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
24 IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
25 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
26 THIS SOFTWARE.
27 ****************************************************************/
28
29 /* The following AMPL copyright notice applies to material added in 2011,
30 identified by #ifndef ASL_OLD_DERIV_CHECK . */
31
32 /*******************************************************************
33 Copyright (C) 2017 AMPL Optimization, Inc.; written by David M. Gay.
34
35 Permission to use, copy, modify, and distribute this software and its
36 documentation for any purpose and without fee is hereby granted,
37 provided that the above copyright notice appear in all copies and that
38 both that the copyright notice and this permission notice and warranty
39 disclaimer appear in supporting documentation.
40
41 The author and AMPL Optimization, Inc. disclaim all warranties with
42 regard to this software, including all implied warranties of
43 merchantability and fitness. In no event shall the author be liable
44 for any special, indirect or consequential damages or any damages
45 whatsoever resulting from loss of use, data or profits, whether in an
46 action of contract, negligence or other tortious action, arising out
47 of or in connection with the use or performance of this software.
48 *******************************************************************/
49
50 #include "asl.h"
51 #include "errchk.h"
52
53 void
report_where(ASL * asl)54 report_where(ASL *asl)
55 {
56 int i, j, k, k1;
57 static const char *what[2] = { "constraint", "objective" };
58 static const char *nfmt[2] = { "%d: ", "function: " };
59 char *b, buf[512];
60 FILE *f;
61
62 fflush(stdout);
63 need_nl = 0;
64 fprintf(Stderr, "Error evaluating ");
65
66 #define next_line fgets(buf,sizeof(buf),f)
67
68 if ((i = cv_index)) {
69 strcpy(stub_end, ".fix");
70 j = 0;
71 if ((f = fopen(filename, "r"))) {
72 for(;;) {
73 if (!next_line)
74 goto eof;
75 for(b = buf; *b; b++)
76 if (*b == '=') {
77 while(++j < i)
78 if (!next_line)
79 goto eof;
80 b = buf;
81 while(*b && *b != '=')
82 b++;
83 if (*b != '=' || b < buf + 2)
84 j = 0;
85 else
86 b[-1] = 0;
87 goto eof;
88 }
89 }
90 eof:
91 fclose(f);
92 }
93 if (j == i)
94 fprintf(Stderr, "var %s: ", buf);
95 else
96 fprintf(Stderr, "\"var =\" definition %d: ", i);
97 goto ret;
98 }
99
100 k = k1 = 0;
101 if ((i = co_index) < 0) {
102 k = 1;
103 i = asl->i.n_con0 -i - 1;
104 if (n_obj <= 1)
105 k1 = 1;
106 }
107 fprintf(Stderr, "%s ", what[k]);
108 if (maxrownamelen) {
109 strcpy(stub_end, ".row");
110 if ((f = fopen(filename, "r"))) {
111 for(j = 0; j <= i; j++)
112 if (!next_line)
113 break;
114 fclose(f);
115 if (j > i) {
116 for(b = buf; *b; b++)
117 if (*b == '\n') {
118 *b = 0;
119 break;
120 }
121 fprintf(Stderr, "%s: ", buf);
122 goto ret;
123 }
124 }
125 }
126 fprintf(Stderr, nfmt[k1], i + 1);
127 ret:
128 errno = 0; /* in case it was set by fopen */
129 fflush(Stderr);
130 }
131
132 static void
jmp_check(Jmp_buf * J,int jv)133 jmp_check(Jmp_buf *J, int jv)
134 {
135 if (J)
136 longjmp(J->jb, jv);
137 }
138
139 static void
Errprint(const char * fmt,...)140 Errprint(const char *fmt, ...)
141 {
142 va_list ap;
143
144 va_start(ap, fmt);
145 #ifndef NO_PERROR
146 if (errno)
147 fprintf(Stderr, "\n%s: ", strerror(errno));
148 #endif
149 vfprintf(Stderr, fmt, ap);
150 va_end(ap);
151 fflush(Stderr);
152 }
153
154 #ifdef ASL_OLD_DERIV_CHECK /*{{*/
deriv_errclear_ASL(Edaginfo * I)155 void deriv_errclear_ASL(Edaginfo *I) {}
deriv_errchk_ASL(ASL * asl,fint * nerror,int coi,int n)156 void deriv_errchk_ASL(ASL *asl, fint *nerror, int coi, int n) {}
157 #else /*}{*/
158 typedef struct DerrRecord DerrRecord;
159 typedef void (*DerrPrint)(ASL*, DerrRecord*);
160
161 struct
162 DerrRecord {
163 DerrPrint errprint;
164 const char *fmt, *who;
165 real a;
166 union { const char *s; real b; } u;
167 int jv;
168 int dv;
169 };
170
171 static void
derrprint1(ASL * asl,DerrRecord * R)172 derrprint1(ASL *asl, DerrRecord *R)
173 {
174 fprintf(Stderr, R->fmt, R->who, R->a);
175 }
176
177 static void
derrprint2(ASL * asl,DerrRecord * R)178 derrprint2(ASL *asl, DerrRecord *R)
179 {
180 fprintf(Stderr, R->fmt, R->who, R->a, R->u.b);
181 }
182
183 static void
derrprintf(ASL * asl,DerrRecord * R)184 derrprintf(ASL *asl, DerrRecord *R)
185 {
186 fprintf(Stderr, R->fmt, R->who, R->u.s);
187 }
188
189 typedef struct DerrMblock DerrMblock;
190 struct
191 DerrMblock {
192 DerrMblock *next;
193 size_t len;
194 real align[1]; /* would prefer align[0], but some older compilers would complain */
195 };
196
197 struct
198 DerivErrInfo {
199 DerrMblock *curmb, *freemb;
200 char *mbnext, *mblast;
201 DerrRecord **R;
202 int *busy;
203 int nbusy;
204 };
205
206 void
deriv_errchk_ASL(ASL * asl,fint * nerror,int coi,int n)207 deriv_errchk_ASL(ASL *asl, fint *nerror, int coi, int n)
208 {
209 DerivErrInfo *D;
210 DerrRecord *R, **Rp, **Rpe;
211 int k;
212
213 D = asl->i.Derrs;
214 if ((k = coi) < 0) {
215 k = -(k + 1);
216 if (k >= nlo)
217 return;
218 k += nlc;
219 }
220 else if (k >= nlc)
221 return;
222 for(Rp = D->R + k, Rpe = Rp + n; Rp < Rpe; ++Rp, ++coi)
223 if ((R = *Rp)) {
224 jmp_check(err_jmp, R->jv);
225 co_index = coi;
226 cv_index = R->dv;
227 report_where(asl);
228 R->errprint(asl,R);
229 fflush(Stderr);
230 jmp_check(err_jmp1, R->jv);
231 exit(1);
232 }
233 }
234
235 static DerivErrInfo *
new_DerrMblock(Edaginfo * I,size_t len)236 new_DerrMblock(Edaginfo *I, size_t len)
237 {
238 DerivErrInfo *D;
239 DerrMblock *M, **Mp;
240 char *s;
241 int nlco;
242 size_t L, L1;
243
244 len = len < 4096
245 ? 4096
246 : (len + sizeof(real) - 1) & ~(sizeof(real) - 1);
247 if (!(D = I->Derrs)) {
248 if ((D = I->Derrs0)) {
249 I->Derrs = D;
250 M = D->curmb;
251 if (M->len >= len)
252 return D;
253 }
254 else {
255 nlco = I->nlc_ + I->nlo_;
256 L = sizeof(DerivErrInfo)
257 + nlco*(sizeof(int) + sizeof(DerrRecord*));
258 L = (L + sizeof(real) - 1) & ~(sizeof(real) - 1);
259 L1 = L + (sizeof(DerrMblock) - sizeof(real)) + len;
260 D = (DerivErrInfo*)M1alloc_ASL(I, L1);
261 memset(D, 0, L);
262 I->Derrs = I->Derrs0 = D;
263 D->R = (DerrRecord**)(D+1);
264 D->busy = (int*)(D->R + nlco);
265 M = (DerrMblock*)((char*)D + L);
266 M->len = len;
267 goto have_M;
268 }
269 }
270 for(Mp = &D->freemb;; Mp = &M->next) {
271 if (!(M = *Mp)) {
272 M = (DerrMblock*)M1alloc_ASL(I, (sizeof(DerrMblock) - sizeof(real)) + len);
273 M->len = len;
274 break;
275 }
276 if (M->len >= len) {
277 *Mp = M->next;
278 break;
279 }
280 }
281 have_M:
282 M->next = D->curmb;
283 D->curmb = M;
284 D->mbnext = s = (char*)M->align;
285 D->mblast = s + M->len;
286 return D;
287 }
288
289 static DerrRecord *
getDR(ASL * asl)290 getDR(ASL *asl)
291 {
292 DerivErrInfo *D;
293 DerrRecord *R;
294 int i, j, je, k;
295 size_t L;
296
297 if ((k = co_index) < 0) {
298 k = -(k + 1);
299 if (k >= nlo)
300 return 0;
301 k += nlc;
302 }
303 else if (k >= nlc)
304 return 0;
305 L = (sizeof(DerrRecord) + sizeof(real)-1) & ~(sizeof(real)-1);
306 if ((D = asl->i.Derrs)) {
307 if (D->R[k])
308 return 0;
309 if (L <= D->mblast - D->mbnext)
310 goto have_D;
311 }
312 D = new_DerrMblock(&asl->i, L);
313 have_D:
314 D->R[k] = R = (DerrRecord*)(D->mblast - L);
315 D->mblast = (char*)R;
316 D->busy[D->nbusy++] = k;
317 if ((R->dv = i = cv_index)) {
318 j = 0;
319 je = nlc + nlo;
320 if (i > comb) {
321 if (i <= combc)
322 je = nlc;
323 else if (i <= ncom0)
324 j = combc;
325 }
326 for(; j < je; ++j) {
327 if (!D->R[j]) {
328 D->R[j] = R;
329 D->busy[D->nbusy++] = j;
330 }
331 }
332 }
333 return R;
334 }
335
336 void
deriv_errclear_ASL(Edaginfo * I)337 deriv_errclear_ASL(Edaginfo *I)
338 {
339 DerivErrInfo *D;
340 DerrMblock *M, *M0, *M1;
341 DerrRecord **R;
342 char *s;
343 int *b, *be;
344
345 D = I->Derrs;
346 I->Derrs = 0;
347 R = D->R;
348 for(b = D->busy, be = b + D->nbusy; b < be; ++b)
349 R[*b] = 0;
350 D->nbusy = 0;
351 M0 = D->freemb;
352 for(M = D->curmb; M; M0 = M, M = M1) {
353 M1 = M->next;
354 M->next = M0;
355 }
356 D->freemb = M0->next;
357 M0->next = 0;
358 D->curmb = M0;
359 D->mbnext = s = (char*)M0->align;
360 D->mblast = s + M0->len;
361 }
362
363 #endif /*}} ASL_OLD_DERIV_CHECK*/
364
365 void
introuble_ASL(ASL * asl,const char * who,real a,int jv)366 introuble_ASL(ASL *asl, const char *who, real a, int jv)
367 {
368 static const char fmt[] = "can't evaluate %s(%g).\n";
369 #ifndef ASL_OLD_DERIV_CHECK /*{*/
370 DerrRecord *R;
371
372 if (jv > 1 && !(want_deriv & 2)) {
373 if ((R = getDR(asl))) {
374 R->errprint = derrprint1;
375 R->a = a;
376 R->jv = jv;
377 R->fmt = fmt;
378 R->who = who;
379 }
380 return;
381 }
382 #endif /*}*/
383 jmp_check(err_jmp, jv);
384 report_where(asl);
385 Errprint(fmt, who, a);
386 jmp_check(err_jmp1, jv);
387 exit(1);
388 }
389
390 void
introuble2_ASL(ASL * asl,const char * who,real a,real b,int jv)391 introuble2_ASL(ASL *asl, const char *who, real a, real b, int jv)
392 {
393 static const char fmt[] = "can't evaluate %s(%g,%g).\n";
394 #ifndef ASL_OLD_DERIV_CHECK /*{*/
395 DerrRecord *R;
396
397 if (jv > 1 && !(want_deriv & 2)) {
398 if ((R = getDR(asl))) {
399 R->errprint = derrprint2;
400 R->a = a;
401 R->u.b = b;
402 R->jv = jv;
403 R->fmt = fmt;
404 R->who = who;
405 }
406 return;
407 }
408 #endif /*}*/
409 jmp_check(err_jmp, jv);
410 report_where(asl);
411 Errprint(fmt, who, a, b);
412 jmp_check(err_jmp1, jv);
413 exit(1);
414 }
415
416 void
zero_div_ASL(ASL * asl,real L,const char * op)417 zero_div_ASL(ASL *asl, real L, const char *op)
418 {
419 errno_set(EDOM);
420 jmp_check(err_jmp, 1);
421 report_where(asl);
422 fprintf(Stderr, "can't compute %g%s0.\n", L, op);
423 fflush(Stderr);
424 jmp_check(err_jmp1, 1);
425 exit(1);
426 }
427
428 void
fintrouble_ASL(ASL * asl,func_info * fi,const char * s,TMInfo * T)429 fintrouble_ASL(ASL *asl, func_info *fi, const char *s, TMInfo *T)
430 {
431 TMInfo *T1, *T1prev;
432 int jv;
433 static const char fmt[] = "Error in function %s:\n\t%s\n";
434
435 jv = 1;
436 switch(*s) {
437 case '\'':
438 jv = 2;
439 goto inc_s;
440 case '"':
441 jv = 3;
442 inc_s:
443 ++s;
444 }
445 #ifndef ASL_OLD_DERIV_CHECK /*{*/
446 if (jv > 1 && !(want_deriv & 2)) {
447 DerivErrInfo *D;
448 DerrRecord *R;
449 size_t L;
450
451 if ((R = getDR(asl))) {
452 D = asl->i.Derrs;
453 L = strlen(s) + 1;
454 if (L > D->mblast - D->mbnext)
455 D = new_DerrMblock(&asl->i, L);
456 memcpy(D->mbnext, s, L);
457 R->u.s = D->mbnext;
458 D->mbnext += L;
459 R->errprint = derrprintf;
460 R->jv = jv;
461 R->fmt = fmt;
462 R->who = fi->name;
463 }
464 return;
465 }
466 #endif /*}*/
467 jmp_check(err_jmp, jv);
468 report_where(asl);
469 fprintf(Stderr, fmt, fi->name, s);
470 fflush(Stderr);
471 for(T1 = T->u.prev; T1; T1 = T1prev) {
472 T1prev = T1->u.prev;
473 free(T1);
474 }
475 jmp_check(err_jmp1,jv);
476 exit(1);
477 }
478