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