1 #include <sys/stat.h>
2 /****************************************************************
3 Copyright (C) 1998, 1999, 2000 Lucent Technologies
4 All Rights Reserved
5 
6 Permission to use, copy, modify, and distribute this software and
7 its documentation for any purpose and without fee is hereby
8 granted, provided that the above copyright notice appear in all
9 copies and that both that the copyright notice and this
10 permission notice and warranty disclaimer appear in supporting
11 documentation, and that the name of Lucent or any of its entities
12 not be used in advertising or publicity pertaining to
13 distribution of the software without specific, written prior
14 permission.
15 
16 LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
18 IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
19 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
21 IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
22 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
23 THIS SOFTWARE.
24 ****************************************************************/
25 
26 #ifdef NO_FUNCADD
27 #include "funcadd.h"
28 
29 const char *ix_details_ASL[] = {0};
30 
31  void
funcadd(AmplExports * ae)32 funcadd(AmplExports *ae)
33 { ae = ae; /* shut up non-use warning */ }
34 
35 #else
36 
37 #ifdef _WIN32
38 #undef WIN32
39 #define WIN32
40 #endif
41 
42 #ifdef WIN32
43 #include "windows.h"
44 #undef void
45 #endif
46 
47 #define _POSIX_SOURCE	/* for HP-UX */
48 
49 #include "stdlib.h"	/* for free() */
50 #include "string.h"
51 #include "funcadd.h"
52 #include "arith.h"	/* for X64_bit_pointers */
53 #include <sys/types.h>
54 #include <sys/stat.h>
55 #ifndef S_IFREG /*{*/
56 #ifdef __S_IFREG
57 #define S_IFREG __S_IFREG
58 #define S_IFDIR __S_IFDIR
59 #elif defined(_S_IFREG)
60 #define S_IFREG _S_IFREG
61 #define S_IFDIR _S_IFDIR
62 #endif
63 #endif /*}*/
64 #ifdef X64_bit_pointers
65 static char Bits[] = "64", BitsAlt[] = "32";
66 #else
67 static char Bits[] = "32", BitsAlt[] = "64";
68 #endif
69 
70 #ifdef Old_APPLE	/* formerly __APPLE__, for earlier versions of Mac OS X */
71 #define FUNCADD "_funcadd_ASL"
72 #endif
73 #ifndef FUNCADD
74 #define FUNCADD "funcadd_ASL"
75 #endif
76 
77 #ifdef __cplusplus
78 extern "C" {
79 extern int libload_ASL(AmplExports *ae, const char *s, int ns, int warn);
80 #endif
81 
82 typedef void Funcadd ANSI((AmplExports*));
83 
84 extern void *mymalloc_ASL ANSI((size_t));
85 #undef mymalloc
86 #define mymalloc(x) mymalloc_ASL((size_t)(x))
87 
88 const char *ix_details_ASL[] = {
89 	"? {show -i options}",
90 	"- {do not import functions: do not access amplfunc.dll}",
91 	"dir {look for amplfunc.dll in directory dir}",
92 	"file {import functions from file rather than amplfunc.dll}",
93 	"",
94 	"When the x of -ix is suitably quoted, multiple files may appear on",
95 	"separate lines or may appear on the same line if each is enclosed",
96 	"by single or double quotes.",
97 	"",
98 	"If no -i option appears but $ampl_funclibs is set, assume",
99 	"-i $ampl_funclibs.  Otherwise, if $AMPLFUNC is set, assume",
100 	"-i $AMPLFUNC.  Otherwise look for amplfunc.dll in the",
101 	"directory that is current when execution begins.",
102 	"",
103 	"-ix and -i x are treated alike.",
104 	0 };
105 #define afdll afdll_ASL
106 extern int aflibname_ASL ANSI((AmplExports*, const char*, const char*, int, Funcadd*, int, void(*)(void*), void*));
107 extern const char *i_option_ASL;
108 
109 #ifdef __cplusplus
110 	}
111 #endif
112 
113 static int first = 1;
114 
115  static int
file_kind(const char * name)116 file_kind(const char *name) /* 1 == regular file, 2 ==> directory; else 0 */
117 {
118 	struct stat sb;
119 
120 	if (stat(name,&sb))
121 		return 0;
122 	if (sb.st_mode & S_IFDIR)
123 		return 2;
124 	if (sb.st_mode & S_IFREG)
125 		return 1;
126 	return 0;
127 	}
128 
129 #ifdef WIN32 /*{{*/
130 
131 #define SLASH '\\'
132 char afdll[] = "\\amplfunc.dll";
133 typedef HINSTANCE shl_t;
134 #define dlopen(x,y) LoadLibrary(x)
135 #define find_dlsym(a,b,c) (a = (Funcadd*)GetProcAddress(b,c))
136 #define dlclose(x) FreeLibrary((HMODULE)x)
137 #define NO_DLERROR
138 
139  static int
Abspath(const char * s)140 Abspath(const char *s)
141 {
142 	int c = *s;
143 	if ((c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')
144 	 && s[1] == ':'
145 	 && (c = s[2]) == '\\' || c == '/')
146 		return 1;
147 	return 0;
148 	}
149 
150 #else /*}{ !WIN32 */
151 
152 #define SLASH '/'
153 
154 char afdll[] = "/amplfunc.dll";
155 
156 #define Abspath(s) (*(s) == '/')
157 
158 #include "unistd.h"	/* for getcwd */
159 #define GetCurrentDirectory(a,b) getcwd(b,(int)(a))
160 
161 #ifdef __hpux /*{{*/
162 #include "dl.h"
163 #define dlopen(x,y) shl_load(x, BIND_IMMEDIATE, 0)
164 #define find_dlsym(a,b,c) !shl_findsym(&b, c, TYPE_PROCEDURE, &a)
165 #define dlclose(x) shl_unload((shl_t)x)
166 #define NO_DLERROR
167 #else /*}{*/
168 #ifdef Old_APPLE /*{{*/
169 #include <mach-o/dyld.h>
170 typedef struct {
171 	NSObjectFileImage ofi;
172 	NSModule m;
173 	char *name;
174 	} NS_pair;
175 typedef NS_pair *shl_t;
176 
177  static void*
find_sym_addr(NS_pair * p,const char * name)178 find_sym_addr(NS_pair *p, const char *name)
179 {
180 	NSSymbol nss;
181 
182 	if (nss = NSLookupSymbolInModule(p->m, name))
183 		return NSAddressOfSymbol(nss);
184 	return 0;
185 	}
186 
187 #define find_dlsym(a,b,c) (a = find_sym_addr(b,c))
188 
189  static void
dlclose(NS_pair * p)190 dlclose(NS_pair *p)
191 {
192 	if (NSUnLinkModule(p->m, NSUNLINKMODULE_OPTION_NONE))
193 		NSDestroyObjectFileImage(p->ofi);
194 	free(p);
195 	}
196 #define NO_DLERROR
197 #else /*}{*/
198 #ifdef __sun__
199 #define __EXTENSIONS__
200 #endif
201 #include "dlfcn.h"
202 typedef void *shl_t;
203 #define find_dlsym(a,b,c) (a = (Funcadd*)dlsym(b,c))
204 #ifdef sun /*{*/
205 #ifndef RTLD_NOW
206 #define RTLD_NOW RTLD_LAZY
207 #endif
208 #endif /* sun }*/
209 #endif /*}} Old_APPLE */
210 #endif /*}} __hpux */
211 #endif /*}} WIN32 */
212 
213 #ifdef __cplusplus
214 extern "C" {
215 #endif
216 
217 #ifdef WIN32
218  static int
wrong_bits(AmplExports * ae,char * name)219 wrong_bits(AmplExports *ae, char *name)
220 {
221 	FILE *f;
222 	IMAGE_DOS_HEADER dh;
223 	int rc;
224 	union { WORD w[2]; DWORD dw; } u;
225 	struct {
226 		IMAGE_FILE_HEADER ifh;
227 		IMAGE_OPTIONAL_HEADER ioh;
228 		} h;
229 #ifdef X64_bit_pointers
230 #define Bits_MAGIC 0x20b
231 #else
232 #define Bits_MAGIC 0x10b
233 #endif
234 	if (!(f = fopen(name, "rb")))
235 		return 1;
236 	rc = 0;
237 	 if (fread(&dh, sizeof(IMAGE_DOS_HEADER), 1, f) != 1
238 	 || dh.e_magic != IMAGE_DOS_SIGNATURE
239 	 || fseek(f, dh.e_lfanew, SEEK_SET)
240 	 || fread(&u, sizeof(u), 1, f) != 1
241 	 || u.dw != IMAGE_NT_SIGNATURE
242 	 || fread(&h, sizeof(h), 1, f) != 1
243 	 || h.ioh.Magic != Bits_MAGIC)
244 		rc = 1;
245 	fclose(f);
246 	return rc;
247 	}
248 #undef Bits_MAGIC
249 #endif
250 
251  static shl_t
dl_open(AmplExports * ae,char * name,int * warned,int * pns)252 dl_open(AmplExports *ae, char *name, int *warned, int *pns)
253 {
254 	FILE *f;
255 	char *d, *d0, *dz, *s;
256 	const char *cs;
257 	int ns;
258 	shl_t h;
259 #ifdef Old_APPLE
260 	NS_pair p;
261 #endif
262 	d = d0 = dz = 0;
263 	for(s = name; *s; ++s)
264 		switch(*s) {
265 		 case '.':
266 			d = s;
267 			break;
268 		 case '/':
269 #ifdef WIN32
270 		 case '\\':
271 #endif
272 			d = 0;
273 		 }
274 	ns = s - name;
275 	if (d
276 	 && d - name > 3
277 	 && d[-3] == '_') {
278 		if (d[-2] == BitsAlt[0]
279 		 && d[-1] == BitsAlt[1]) {
280 			d[-2] = Bits[0];
281 			d[-1] = Bits[1];
282 			dz = d;
283 			d = 0;
284 			}
285 		else if (d[-2] == Bits[0]
286 		 && d[-1] == Bits[1]) {
287 			dz = d;
288 			d = 0;
289 			}
290 		}
291  tryagain:
292 #ifdef Old_APPLE
293 	NSObjectFileImageReturnCode irc;
294 	irc = NSCreateObjectFileImageFromFile(name,&p.ofi);
295 	h = 0;
296 	if (irc == NSObjectFileImageSuccess) {
297 		p.m = NSLinkModule(p.ofi, name,
298 			  NSLINKMODULE_OPTION_BINDNOW
299 			| NSLINKMODULE_OPTION_PRIVATE
300 			| NSLINKMODULE_OPTION_RETURN_ON_ERROR);
301 		if (!p.m)
302 			fprintf(stderr, "NSLinkModule(\"%s\") failed.\n", name);
303 		else {
304 			h = (NS_pair*)mymalloc(sizeof(NS_pair) + strlen(name) + 1);
305 			strcpy(p.name = (char*)(h+1), name);
306 			memcpy(h, &p, sizeof(NS_pair));
307 			}
308 		}
309 	else if (irc != NSObjectFileImageAccess)
310 		fprintf(stderr,
311 			"return %d from NSCreateObjectFileImageFromFile(\"%s\")\n",
312 			irc, name);
313 #else
314 #ifdef WIN32 /*{*/ /* make sure name is for the right number of bits */
315 	if (wrong_bits(ae, name))
316 		h = 0;
317 	else
318 #endif /*}*/
319 	h = dlopen(name, RTLD_NOW);
320 #endif
321 	if (!h) {
322 		if (d) {
323 			do s[3] = s[0]; while(--s >= d);
324 			d[0] = '_';
325 			d[1] = Bits[0];
326 			d[2] = Bits[1];
327 			d0 = d;
328 			d = 0;
329 			ns += 3;
330 			goto tryagain;
331 			}
332 		if (dz) {
333 			for(d = dz-3; (*d = *dz); ++d, ++dz);
334 			d = dz = 0;
335 			goto tryagain;
336 			}
337 		if (d0)
338 			for(s = d0; (s[0] = s[3]); ++s);
339 		if (!*warned && (f = fopen(name,"rb"))) {
340 			fclose(f);
341 			if (file_kind(name) == 1) {
342 #ifdef NO_DLERROR
343 				*warned = 1;
344 				fprintf(Stderr, "Cannot load library \"%s\".\n", name);
345 #else
346 				/* get dlerror() for original name */
347 				if (!d0 || !(h = dlopen(name, RTLD_NOW))) {
348 					*warned = 1;
349 					fprintf(Stderr, "Cannot load library \"%s\"", name);
350 					cs = dlerror();
351 					fprintf(Stderr, cs ? ":\n%s\n" : ".\n", cs);
352 					}
353 #endif
354 				}
355 			}
356 		}
357 	*pns = ns;
358 	return h;
359 	}
360 
361  static void
dl_close(void * h)362 dl_close(void *h)
363 {
364 #ifdef CLOSE_AT_RESET
365 	first = 1;
366 #endif
367 	if (h)
368 		dlclose(h);
369 	}
370 
371  int
libload_ASL(AmplExports * ae,const char * s,int ns,int warn)372 libload_ASL(AmplExports *ae, const char *s, int ns, int warn)
373 {
374 	Funcadd *fa;
375 	char buf0[2048], *buf;
376 	int ns1, rc, rcnf, warned;
377 	shl_t h;
378 	size_t n, nx;
379 
380 	nx = 0;
381 	buf = buf0;
382 	if (!Abspath(s)) {
383 		if (!GetCurrentDirectory(sizeof(buf0),buf0))
384 			return 2;
385 		nx = strlen(buf0);
386 		}
387 	n = ns + sizeof(afdll) + nx + 3; /* +3 for inserting _32 or _64 */
388 	if (n > sizeof(buf0)) {
389 		buf = (char*)mymalloc(n);
390 		if (nx)
391 			memcpy(buf, buf0, nx);
392 		}
393 	if (nx)
394 		buf[nx++] = SLASH;
395 	strncpy(buf+nx, s, ns);
396 	buf[nx+ns] = 0;
397 	rc = warned = 0;
398 	rcnf = warn >> 1;
399 	warn &= 1;
400 	if ((h = dl_open(ae, buf, &warned, &ns1))) {
401  found:
402 		if (find_dlsym(fa, h, FUNCADD)
403 		 || find_dlsym(fa, h, "funcadd")) {
404 #ifdef CLOSE_AT_RESET
405 			aflibname_ASL(ae,buf,buf+nx,ns1-nx,fa,0,dl_close,h);
406 				/* -DCLOSE_AT_RESET is for use in shared */
407 				/* libraries, such as MATLAB mex functions, */
408 				/* that may be loaded and unloaded several */
409 				/* times during execution of the program. */
410 #else
411 			aflibname_ASL(ae,buf,buf+nx,ns1-nx,fa,1,dl_close,h);
412 #endif
413 			}
414 		else {
415 			fprintf(stderr, "Could not find funcadd in %s\n", buf);
416 			dl_close(h);
417 			rc = 3;
418 			}
419 		}
420 	else if (warn) {
421 		if (!warned) {
422 			strcpy(buf+nx+ns, afdll);
423 			if ((h = dl_open(ae, buf, &warned, &ns1)))
424 				goto found;
425 			}
426 		if (warned)
427 			rc = 2;
428 		else
429 			goto notfound;
430 		}
431 	else {
432  notfound:
433 		rc = rcnf;
434 		if (warn) {
435 			buf[nx+ns] = 0;
436 			if (file_kind(buf) == 2) {
437 				buf[nx+ns] = SLASH;
438 				fprintf(Stderr, "Cannot find library \"%s\".\n", buf);
439 				}
440 			else
441 				fprintf(Stderr, "Cannot find library \"%.*s\".\n", ns, s);
442 			}
443 		}
444 	if (buf != buf0)
445 		free(buf);
446 	return rc;
447 	}
448 
449  static int
libloop(AmplExports * ae,const char * s)450 libloop(AmplExports *ae, const char *s)
451 {
452 	const char *s1, *s2;
453 	int c, ns, rc;
454 
455 	for(rc = 0;; s = s1) {
456 		while(*s <= ' ')
457 			if (!*s++)
458 				goto ret;
459 		if (*s == '"' || *s == '\'') {
460 			c = *s++;
461 			for(s1 = s; *s1 != c; ++s1)
462 				if (!*s1)
463 					goto ret;
464 			if (s1 == s)
465 				goto ret;
466 			s2 = s1++;
467 			}
468 		else {
469 			for(s1 = s; *++s1 >= ' '; );
470 			for(s2 = s1; s2[-1] == ' '; --s2);
471 			}
472 		ns = s2 - s;
473 		if (libload_ASL(ae, s, ns, 1))
474 			++rc;
475 		}
476  ret:
477 	return rc;
478 	}
479 
480 int n_badlibs_ASL;
481 
482  void
funcadd(AmplExports * ae)483 funcadd(AmplExports *ae)
484 {
485 	const char *s;
486 	int nb = 0;
487 
488 	if (first) {
489 		first = 0;
490 		if ((s = i_option_ASL)) {
491 			if (!*s || (*s == '-' && !s[1]))
492 				return;
493 			nb += libloop(ae, s);
494 			}
495 		else
496 			nb = libload_ASL(ae, afdll+1, (int)sizeof(afdll)-2, 0);
497 		}
498 	n_badlibs_ASL = nb;
499 	}
500 
501 #ifdef __cplusplus
502 }
503 #endif
504 
505 #endif /* NO_FUNCADD */
506