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