1 /****************************************************************
2 Copyright (C) 1997-2000 Lucent Technologies
3 All Rights Reserved
4 
5 Permission to use, copy, modify, and distribute this software and
6 its documentation for any purpose and without fee is hereby
7 granted, provided that the above copyright notice appear in all
8 copies and that both that the copyright notice and this
9 permission notice and warranty disclaimer appear in supporting
10 documentation, and that the name of Lucent or any of its entities
11 not be used in advertising or publicity pertaining to
12 distribution of the software without specific, written prior
13 permission.
14 
15 LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17 IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20 IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22 THIS SOFTWARE.
23 ****************************************************************/
24 
25 #include "asl.h"
26 
27 #ifdef __cplusplus
28 extern "C" {
29 #endif
30 extern ASLhead ASLhead_ASL;
31 
32 char *i_option_ASL;
33 static int n_added;
34 
35  func_info *
36 #ifdef KR_headers
func_lookup(asl,s,add)37 func_lookup(asl, s, add) ASL *asl; register char *s; int add;
38 #else
39 func_lookup(ASL *asl, register const char *s, int add)
40 #endif
41 {
42 	register unsigned x = 0;
43 	func_info *fi, **finext;
44 	Const char *s0 = s;
45 
46 	while(*s)
47 		x = 31*x + *s++;
48 	finext = &fhash[x % NFHASH];
49 	for(fi = *finext; fi; fi = fi->next)
50 		if (!strcmp(s0, fi->name)) {
51 			if (add) {
52 				fprintf(Stderr,
53 				"addfunc: duplicate function %s\n", s0);
54 				fi = 0;
55 				}
56 			return fi;
57 			}
58 	if (add) {
59 		fi = (func_info *)mem_ASL(asl, sizeof(func_info));
60 		fi->next = *finext;
61 		*finext = fi;
62 		fi->name = s0;
63 		}
64 	return fi;
65 	}
66 
67  void
68 #ifdef KR_headers
addfunc_ASL(fname,f,ftype,nargs,funcinfo,ae)69 addfunc_ASL(fname, f, ftype, nargs, funcinfo, ae)
70 	char *fname, *funcinfo; ufunc *f; AmplExports *ae;
71 #else
72 addfunc_ASL(const char *fname, ufunc *f, int ftype, int nargs, void *funcinfo, AmplExports *ae)
73 #endif
74 {
75 	register func_info *fi;
76 	ASL *asl = (ASL*)ae->asl;
77 	if (ftype && ftype != 1) {
78 #ifndef COMPLAIN_AT_BAD_FTYPE
79 		if (ftype < 0 || ftype > 6)
80 #endif
81 		{
82 		fprintf(Stderr, "function %s: ftype = %d; expected 0 or 1\n",
83 			fname, ftype);
84 		exit(1);
85 		}
86 #ifndef COMPLAIN_AT_BAD_FTYPE
87 		return;
88 #endif
89 		}
90 	if (fi = func_lookup(asl, fname, 1)) {
91 		n_added++;
92 		fi->funcp = f;
93 		fi->ftype = ftype;
94 		fi->nargs = nargs;
95 		fi->funcinfo = funcinfo;
96 		if (!funcsfirst)
97 			funcsfirst = fi;
98 		else
99 			funcslast->fnext = fi;
100 		funcslast = fi;
101 		fi->fnext = 0;
102 		}
103 	}
104 
105 enum { NEFB = 5, NEFB0 = 2 };
106 
107  static Exitcall a_e_info[NEFB0];
108  static Exitcall *a_e_next = a_e_info;
109  static Exitcall *a_e_last = a_e_info + NEFB0;
110  static Exitcall *a_e_prev;
111 
112  typedef struct
113 ExitCallInfo { Exitcall *cur, **curp, *last, **lastp; } ExitCallInfo;
114 
115  static void
116 #ifdef KR_headers
AtReset1(ae,ef,v,eci)117 AtReset1(ae, ef, v, eci) AmplExports *ae; Exitfunc *ef; char *v;
118 			 ExitCallInfo *eci;
119 #else
120 AtReset1(AmplExports *ae, Exitfunc *ef, void *v, ExitCallInfo *eci)
121 #endif
122 {
123 	Exitcall *ec;
124 	ASL *asl = (ASL*)ae->asl;
125 	if (eci) {
126 		eci->cur = asl->i.arprev;
127 		eci->curp = &asl->i.arprev;
128 		eci->last = asl->i.arlast;
129 		eci->lastp = &asl->i.arlast;
130 		}
131 	if (asl->i.arnext >= asl->i.arlast) {
132 		asl->i.arnext = (Exitcall*)M1alloc(NEFB*sizeof(Exitcall));
133 		asl->i.arlast = asl->i.arnext + NEFB;
134 		}
135 	asl->i.arnext->prev = asl->i.arprev;
136 	asl->i.arprev = ec = asl->i.arnext++;
137 	ec->ef = ef;
138 	ec->v = v;
139 	}
140 
141  static void
142 #ifdef KR_headers
AtReset(ae,ef,v)143 AtReset(ae, ef, v) AmplExports *ae; Exitfunc *ef; char *v;
144 #else
145 AtReset(AmplExports *ae, Exitfunc *ef, void *v)
146 #endif
147 { AtReset1(ae, ef, v, 0); }
148 
149 
150  void
151 #ifdef KR_headers
at_end_ASL(ec)152 at_end_ASL(ec) Exitcall *ec;
153 #else
154 at_end_ASL(Exitcall *ec)
155 #endif
156 {
157 	while(ec) {
158 		(*ec->ef)(ec->v);
159 		ec = ec->prev;
160 		}
161 	}
162 
163  void
at_exit_ASL(VOID)164 at_exit_ASL(VOID)
165 {
166 	Exitcall *ec;
167 	ASLhead *h, *h0;
168 
169 	h0 = &ASLhead_ASL;
170 	h = ASLhead_ASL.next;
171 	h0->next = h0->prev = h0;
172 	for(; h != h0; h = h->next)
173 		if (ec = ((ASL*)h)->i.arprev)
174 			at_end_ASL(ec);
175 	if (ec = a_e_prev) {
176 		a_e_prev = 0;
177 		at_end_ASL(ec);
178 		}
179 	}
180 
181  static void
182 #ifdef KR_headers
AtExit1(ae,ef,v,eci)183 AtExit1(ae, ef, v, eci) AmplExports *ae; Exitfunc *ef; char *v;
184 			ExitCallInfo *eci;
185 #else
186 AtExit1(AmplExports *ae, Exitfunc *ef, void *v, ExitCallInfo *eci)
187 #endif
188 {
189 	Exitcall *ec;
190 	Not_Used(ae);
191 #ifndef NO_ONEXIT
192 	if (!a_e_prev)
193 		atexit(at_exit_ASL); /* in case mainexit() is bypassed */
194 #endif
195 	if (eci) {
196 		eci->cur = a_e_prev;
197 		eci->curp = &a_e_prev;
198 		eci->last = a_e_last;
199 		eci->lastp = &a_e_last;
200 		}
201 	if (a_e_next >= a_e_last) {
202 		a_e_next = (Exitcall*)mymalloc(NEFB*sizeof(Exitcall));
203 		a_e_last = a_e_next + NEFB;
204 		}
205 	a_e_next->prev = a_e_prev;
206 	a_e_prev = ec = a_e_next++;
207 	ec->ef = ef;
208 	ec->v = v;
209 	}
210 
211  static void
212 #ifdef KR_headers
AtExit(ae,ef,v)213 AtExit(ae, ef, v) AmplExports *ae; Exitfunc *ef; char *v;
214 #else
215 AtExit(AmplExports *ae, Exitfunc *ef, void *v)
216 #endif
217 { AtExit1(ae, ef, v, 0); }
218 
219  struct
220 TMInfo {
221 	union {
222 		TMInfo *prev;
223 		double align;
224 		} u;
225 	};
226 
227  static Char *
228 #ifdef KR_headers
Tempmem(T,L)229 Tempmem(T, L) TMInfo *T; size_t L;
230 #else
231 Tempmem(TMInfo *T, size_t L)
232 #endif
233 {
234 	TMInfo *T1 = (TMInfo *)mymalloc(L + sizeof(TMInfo));
235 	T1->u.prev = T->u.prev;
236 	T->u.prev = T1;
237 	return (Char*)(T1+1);
238 	}
239 
240 #ifdef KR_headers
241  static void
242 No_table_handler(Dbread, Dbwrite, hname, flags, vinfo)
243 	int (*Dbread)(), (*Dbwrite)(), flags;
244 	char *hname; Char *vinfo;
245 {}
246 
247  static cryptblock*
No_crypto(key,scrbytes)248 No_crypto(key, scrbytes) char *key; size_t scrbytes;
249 #else
250  static void
251 No_table_handler(
252 	int (*Dbread)(AmplExports*, TableInfo*),
253 	int (*Dbwrite)(AmplExports*, TableInfo*),
254 	char *hname,
255 	int flags,
256 	void *vinfo)
257 {}
258 
259  static cryptblock*
260 No_crypto(char *key, size_t scrbytes)
261 #endif
262 { return 0; }
263 
264 typedef void Funcadd ANSI((AmplExports*));
265 
266 #ifndef CLOSE_AT_RESET
267 static Funcadd *Fa0[4], **Fa = Fa0;
268 static int nFa = 0, nFamax = 4;
269 #endif
270 
271 #ifdef SYMANTEC
272 #define No_popen_or_pclose
273 typedef char *(*Tempnamtype)(const char*, const char*);
274 #define Tempnam_cast (Tempnamtype)
275 #endif
276 
277 #ifdef WATCOM
278 #define tempnam _tempnam
279 #endif
280 
281 #ifdef NO_tempnam
282 
283 /* If the system does not provide a true tempnam function */
284 /* the AMPL/solver interface library will not do so either. */
285 
286  static char *
tempnam(const char * dir,const char * pfx)287 tempnam(const char *dir, const char *pfx)
288 { return 0; }
289 #endif /* NO_tempnam */
290 
291 #ifdef _WIN32
292 #define popen _popen
293 #define pclose _pclose
294 #else
295 #ifdef MSDOS
296 #undef  No_popen_or_pclose
297 #define No_popen_or_pclose
298 #endif
299 #endif
300 
301 #ifdef No_popen_or_pclose
302 #undef popen
303 #define popen no_popen
304 #undef pclose
305 #define pclose no_pclose
306 
307  static int
no_pclose(FILE * f)308 no_pclose(FILE*f) { return 1; }
309 
310  static FILE*
no_popen(const char * cmd,const char * type)311 no_popen(const char*cmd, const char*type) { return 0; }
312 #endif
313 
314  static AmplExports AE;
315 
316 #ifdef clearerr
317  static void
318 #ifdef KR_headers
myclearerr(f)319 myclearerr(f) FILE *f;
320 #else
321 myclearerr(FILE *f)
322 #endif
323 { clearerr(f); }
324 #undef clearerr
325 #define clearerr myclearerr
326 #endif /*clearerr*/
327 
328 #ifdef feof
329  static int
330 #ifdef KR_headers
myfeof(f)331 myfeof(f) FILE *f;
332 #else
333 myfeof(FILE *f)
334 #endif
335 { return feof(f); }
336 #undef feof
337 #define feof myfeof
338 #endif /*feof*/
339 
340 #ifdef ferror
341  static int
342 #ifdef KR_headers
myferror(f)343 myferror(f) FILE *f;
344 #else
345 myferror(FILE *f)
346 #endif
347 { return ferror(f); }
348 #undef ferror
349 #define ferror myferror
350 #endif /*ferror*/
351 
352 #ifdef _fileno
353 #undef fileno
354 #define fileno _fileno
355 #endif
356 
357 #ifdef fileno
358  static int
359 #ifdef KR_headers
myfileno(f)360 myfileno(f) FILE *f;
361 #else
362 myfileno(FILE *f)
363 #endif
364 { return fileno(f); }
365 #undef fileno
366 #define fileno myfileno
367 #endif /* fileno */
368 
369 #ifndef Tempnam_cast
370 #define Tempnam_cast /*nothing*/
371 #endif
372 
373 #ifdef __linux__
374 #define USE_MKSTEMP
375 #endif
376 #ifdef USE_MKSTEMP
377  /* Shut up warnings about tempnam and tmpnam. */
378 #include <sys/types.h>
379 #include <sys/stat.h>
380 #include <unistd.h>
381 
382  static int
isdir(const char * s)383 isdir(const char *s)
384 {
385 	struct stat sbuf;
386 	if (stat(s, &sbuf))
387 		return 0;
388 	return S_ISDIR(sbuf.st_mode);
389 	}
390 
391  static char *
my_tempnam(const char * dir,const char * pfx,char * s)392 my_tempnam(const char *dir, const char *pfx, char *s)
393 {
394 	const char *c;
395 	int i;
396 	size_t Ld, Lp;
397 
398 	if ((c = getenv("TMPDIR")) && isdir(c))
399 		dir = c;
400 	else if (!dir || !isdir(dir))
401 		dir = "/tmp";
402 	if (!pfx)
403 		pfx = "";
404 	Ld = strlen(dir);
405 	Lp = strlen(pfx);
406 	if (!s)
407 		s = Malloc(Ld + Lp + 8);
408 	strcpy(s, dir);
409 	if (s[Ld-1] != '/')
410 		s[Ld++] = '/';
411 	strcpy(s+Ld, pfx);
412 	strcpy(s + Ld + Lp, "XXXXXX");
413 	if (i = mkstemp(s))
414 		close(i);
415 	else {
416 		free(s);
417 		s = 0;
418 		}
419 	return s;
420 	}
421 
422  static char *
Tempnam(const char * dir,const char * pfx)423 Tempnam(const char *dir, const char *pfx)
424 { return my_tempnam(dir,pfx,0); }
425 
426  static char *
Tmpnam(char * s)427 Tmpnam(char *s)
428 {
429 	static char *s0;
430 	if (s)
431 		return my_tempnam(0,"Temp_",s);
432 	if (s0)
433 		free(s0);
434 	return s0 = my_tempnam(0,"Temp_",0);
435 	}
436 #undef tempnam
437 #define tempnam Tempnam
438 #undef tmpnam
439 #define tmpnam Tmpnam
440 #endif /* USE_MKSTEMP */
441 
442  void (*breakfunc_ASL) ANSI((int,void*)), *breakarg_ASL;
443 
444  void
445 #ifdef KR_headers
func_add(asl)446 func_add(asl) ASL *asl;
447 #else
448 func_add(ASL *asl)
449 #endif
450 {
451 	AmplExports *ae;
452 
453 	if (need_funcadd) {
454 		if (!i_option_ASL
455 		 && !(i_option_ASL = getenv("ampl_funclibs")))
456 		      i_option_ASL = getenv("AMPLFUNC");
457 		if (!AE.PrintF) {
458 			AE.StdIn = stdin;
459 			AE.StdOut = stdout;
460 			AE.StdErr = Stderr;
461 			AE.ASLdate = ASLdate_ASL;
462 			AE.Addfunc = addfunc_ASL;
463 			AE.PrintF = printf;
464 			AE.FprintF = fprintf;
465 			AE.SprintF = sprintf;
466 			AE.SnprintF = snprintf;
467 			AE.VfprintF = vfprintf;
468 			AE.VsprintF = vsprintf;
469 			AE.VsnprintF = vsnprintf;
470 			AE.Strtod = strtod;
471 			AE.AtExit = AtExit;
472 			AE.AtReset = AtReset;
473 			AE.Tempmem = Tempmem;
474 			AE.Add_table_handler = No_table_handler;
475 			AE.Crypto = No_crypto;
476 			AE.Qsortv = qsortv;
477 			AE.Clearerr = clearerr;
478 			AE.Fclose = fclose;
479 			AE.Fdopen = fdopen;
480 			AE.Feof = feof;
481 			AE.Ferror = ferror;
482 			AE.Fflush = fflush;
483 			AE.Fgetc = fgetc;
484 			AE.Fgets = fgets;
485 			AE.Fileno = fileno;
486 			AE.Fopen = fopen;
487 			AE.Fputc = fputc;
488 			AE.Fputs = fputs;
489 			AE.Fread = fread;
490 			AE.Freopen = freopen;
491 			AE.Fscanf = fscanf;
492 			AE.Fseek = fseek;
493 			AE.Ftell = ftell;
494 			AE.Fwrite = fwrite;
495 			AE.Pclose = pclose;
496 			AE.Perror = perror;
497 			AE.Popen = popen;
498 			AE.Puts = puts;
499 			AE.Rewind = rewind;
500 			AE.Scanf = scanf;
501 			AE.Setbuf = setbuf;
502 			AE.Setvbuf = setvbuf;
503 			AE.Sscanf = sscanf;
504 			AE.Tempnam = Tempnam_cast tempnam;
505 			AE.Tmpfile = tmpfile;
506 			AE.Tmpnam = tmpnam;
507 			AE.Ungetc = ungetc;
508 			AE.Getenv = getenv_ASL;
509 			AE.Breakfunc = breakfunc_ASL;
510 			AE.Breakarg = breakarg_ASL;
511 			}
512 		if (AE.asl)
513 			memcpy(ae = (AmplExports*)M1alloc(sizeof(AmplExports)),
514 				&AE, sizeof(AmplExports));
515 		else
516 			ae = &AE;
517 		asl->i.ae = ae;
518 		ae->asl = (Char*)asl;
519 		auxinfo_ASL(ae);
520 #ifndef CLOSE_AT_RESET
521 		if (nFa > 0) {
522 			/* not the first nl_reader call */
523 			int i = 0;
524 			while(i < nFa)
525 				(*Fa[i++])(ae);
526 			}
527 		else
528 #endif
529 			funcadd(ae);
530 		need_funcadd = 0;
531 		}
532 	}
533 
534  void
535 #ifdef KR_headers
show_funcs_ASL(asl)536 show_funcs_ASL(asl) ASL *asl;
537 #else
538 show_funcs_ASL(ASL *asl)
539 #endif
540 {
541 	func_info *fi;
542 	int nargs;
543 	char *atleast;
544 
545 	func_add(asl);
546 	fprintf(Stderr, "Available nonstandard functions:%s\n",
547 		(fi = funcsfirst) ? "" : " none");
548 	for(; fi; fi = fi->fnext) {
549 		if ((nargs = fi->nargs) >= 0)
550 			atleast = "";
551 		else {
552 			nargs = -(1 + nargs);
553 			atleast = "at least ";
554 			}
555 		fprintf(Stderr, "\t%s(%s%d %sarg%s)\n", fi->name,
556 			atleast, nargs, fi->ftype ? "" : "real ",
557 			nargs == 1 ? "" : "s");
558 		}
559 	fflush(Stderr);
560 	}
561 
562  int
563 #ifdef KR_headers
aflibname_ASL(ae,fullname,name,nlen,fa,save_fa,dl_close,h)564 aflibname_ASL(ae, fullname, name, nlen, fa, save_fa, dl_close, h)
565 	AmplExports *ae; char *fullname; char *name; int nlen; Funcadd *fa;
566 	int save_fa; void (*dl_close)(), *h;
567 #else
568 aflibname_ASL(AmplExports *ae, char *fullname, char *name, int nlen,
569 	Funcadd *fa, int save_fa, void (*dl_close)(void*), void *h)
570 #endif
571 {
572 	Exitcall *ec;
573 	ExitCallInfo eci;
574 	Not_Used(fullname);
575 	Not_Used(name);
576 	Not_Used(nlen);
577 	n_added = 0;
578 	if (save_fa)
579 		AtExit1( ae, dl_close, h, &eci);
580 	else
581 		AtReset1(ae, dl_close, h, &eci);
582 	(*fa)(ae);
583 	if (!n_added) {
584 		for(ec = *eci.curp; ec != eci.cur; ec = ec->prev)
585 			(*ec->ef)(ec->v);
586 		*eci.curp = ec;
587 		*eci.lastp = eci.last;
588 		/* A small storage leak is possible if a new block of */
589 		/* Exitcalls was allocated, but since the present !n_added */
590 		/* case is unlikely, this leak should be of little concern. */
591 		}
592 #ifndef CLOSE_AT_RESET
593 	else if (save_fa) {
594 		if (++nFa >= nFamax) {
595 			Funcadd **Fa1;
596 			nFamax <<= 1;
597 			Fa1 = (Funcadd**)Malloc(nFamax * sizeof(Funcadd*));
598 			memcpy(Fa1, Fa, nFa*sizeof(Funcadd*));
599 			if (Fa != Fa0)
600 				free(Fa);
601 			Fa = Fa1;
602 			}
603 		Fa[nFa-1] = fa;
604 		}
605 #endif /* !CLOSE_AT_RESET */
606 	return n_added;
607 	}
608 #ifdef __cplusplus
609 }
610 #endif
611 /* Last relevant change to asl.h: 19991013. */
612