/[ascend]/trunk/base/generic/compiler/importhandler.c
ViewVC logotype

Contents of /trunk/base/generic/compiler/importhandler.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1597 - (show annotations) (download) (as text)
Fri Aug 17 05:26:05 2007 UTC (17 years, 1 month ago) by jpye
File MIME type: text/x-csrc
File size: 15450 byte(s)
New external library naming scheme on Windows: 'name_ascend.dll' instead of 'name.dll'.
This applies to solvers as well as external methods, extpy, import handlers, etc.
1 /* ASCEND modelling environment
2 Copyright (C) 2006 Carnegie Mellon University
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18 *//**
19 @file
20 Handle the Import Handler library, which is a hash table of additional
21 handlers for external scripts in the IMPORT statement.
22 *//*
23 by John Pye
24 Created Sept 26, 2006
25 */
26
27 #include "importhandler.h"
28
29 #include <utilities/config.h>
30 #include <utilities/error.h>
31 #include <utilities/ascDynaLoad.h>
32 #include <utilities/ascPanic.h>
33 #include <utilities/ascEnvVar.h>
34 #include <general/table.h>
35
36 #include <string.h>
37
38 /* #define SEARCH_DEBUG */
39 /* #define IMPORTHANDLER_VERBOSE */
40
41 /*
42 Maximum number of importhandlers possible in one session. Hard to imagine
43 that you would want more than this.
44 */
45 #define IMPORTHANDLER_MAX 10
46
47 /**
48 List of import handlers currently in effect. @TODO this shouldn't be a global,
49 but unfortunately such globals are 'The ASCEND Way'.
50 */
51 struct ImportHandler **importhandler_library=NULL;
52
53 /**
54 Table of registered pointers for use in passing GUI data out to external scripts.
55 */
56 struct Table *importhandler_sharedpointers=NULL;
57
58 ASC_DLLSPEC int importhandler_add(struct ImportHandler *handler){
59 int i;
60 if(handler==NULL){
61 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Handler is NULL");
62 return 2;
63 }
64 if(importhandler_library == NULL){
65 importhandler_createlibrary();
66 }
67 for(i=0; i< IMPORTHANDLER_MAX; ++i){
68 if(importhandler_library[i] == NULL)break;
69 if(importhandler_library[i]->name == handler->name){
70 ERROR_REPORTER_HERE(ASC_USER_NOTE,"Handler already loaded");
71 return 0;
72 }
73 }
74 if(i==IMPORTHANDLER_MAX){
75 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Too many import handlers register (IMPORTHANDLER_MAX=%d)",IMPORTHANDLER_MAX);
76 return 1;
77 }
78 importhandler_library[i] = handler;
79 ERROR_REPORTER_HERE(ASC_USER_NOTE,"New import hander '%s' added",handler->name);
80 return 0;
81 }
82
83 /* Function to attempt import of an external script
84 @param partialname Name of the external script (without extension), relative to PATH.
85 @param defaultpath Default value of file search PATH. Is trumped by value of pathenvvar if present in environment.
86 @param pathenvvar Environment variable containing the user's preferred file search path value.
87 @return 0 on success
88 */
89 int importhandler_attemptimport(const char *partialname,const char *defaultpath, const char *pathenvvar){
90 ERROR_REPORTER_HERE(ASC_PROG_ERR,"%s not implemented",__FUNCTION__);
91 return 1;
92 }
93
94 /*------------------------------------------------------------------------------
95 DEFAULT IMPORT HANDLER FOR DLL/SO FILES
96 */
97
98 /**
99 Create a filename for an external library (DLL/SO) based on a
100 partial filename.
101
102 @param partialname The partial filename (eg 'mylib')
103 @return Complete filename (eg 'libmylib.so' or 'mylib.dlll', etc)
104 */
105 char *importhandler_extlib_filename(const char *partialname){
106 char *buffer;
107 buffer = ASC_NEW_ARRAY(char,PATH_MAX);
108
109 #if defined(ASC_EXTLIBSUFFIX) && defined(ASC_EXTLIBPREFIX)
110 /*
111 this is the preferred operation: SCons reports what the local system
112 uses as its shared library file extension.
113 */
114 snprintf(buffer,PATH_MAX,"%s%s%s",ASC_EXTLIBPREFIX,partialname,ASC_EXTLIBSUFFIX);
115 #else
116 #ifdef __GNUC__
117 # warning "You should be using Use ASC_EXTLIBPREFIX and ASC_EXTLIBSUFFIX!"
118 #endif
119 /**
120 @DEPRECATED
121
122 If we don't have ASC_EXTLIB-SUFFIX and -PREFIX then we can do some
123 system-specific stuff here, but it's not as general.
124 */
125 # ifdef __WIN32__
126 snprintf(buffer,PATH_MAX,"%s.dll",partialname);
127 # elif defined(linux)
128 snprintf(buffer,PATH_MAX,"lib%s.so",partialname); /* changed from .o to .so -- JP */
129 # elif defined(sun) || defined(solaris)
130 snprintf(buffer,PATH_MAX,"%s.so.1.0",partialname);
131 # elif defined(__hpux)
132 snprintf(buffer,PATH_MAX,"%s.sl",partialname);
133 # elif defined(_SGI_SOURCE)
134 snprintf(buffer,PATH_MAX,"%s.so",partialname);
135 # else
136 # error "Unknown system type (please define ASC_EXTLIBSUFFIX and ASC_EXTLIBPREFIX)"
137 # endif
138 #endif
139
140 return buffer;
141 }
142
143 /**
144 Perform the actual importing of an external DLL/SO in to ASCEND. Can assume
145 that the file exists and is readable.
146
147 @param fp Location of DLL/SO file
148 @param initfunc Name of registration function, preferably NULL (so that ASCEND automatically determines it)
149 @param partialpath as specified in 'IMPORT' statement, for creation of auto_initfunc name
150 @return 0 on success
151 */
152 int importhandler_extlib_import(const struct FilePath *fp,const char *initfunc,const char *partialpath){
153
154 struct FilePath *fp1;
155 char *stem;
156 char *path;
157 char auto_initfunc[PATH_MAX];
158 int result;
159
160 path = ospath_str(fp);
161 if(path==NULL){
162 ERROR_REPORTER_HERE(ASC_PROG_ERR,"File path is NULL");
163 return 1;
164 }
165
166 if(initfunc==NULL){
167 fp1 = ospath_new(partialpath);
168 stem = ospath_getbasefilename(fp1);
169 strncpy(auto_initfunc,stem,PATH_MAX);
170 ospath_free(fp1);
171 ASC_FREE(stem);
172
173 strncat(auto_initfunc,"_register",PATH_MAX-strlen(auto_initfunc));
174 /* CONSOLE_DEBUG("Created auto-initfunc name '%s'",auto_initfunc); */
175 result = Asc_DynamicLoad(path,auto_initfunc);
176 }else{
177 result = Asc_DynamicLoad(path,initfunc);
178 }
179
180 if(result){
181 CONSOLE_DEBUG("FAILED TO IMPORT '%s' (error %d)",partialpath,result);
182 }else{
183 if(initfunc==NULL){
184 CONSOLE_DEBUG("Successfully ran '%s' (automatically named) from dynamic package '%s'",auto_initfunc,path);
185 }else{
186 CONSOLE_DEBUG("Successfully ran '%s' from dynamic package '%s'",initfunc,path);
187 }
188 }
189
190 ASC_FREE(path);
191 return result;
192 }
193
194 /*------------------------------------------------------------------------------
195 LIST-BASED FUNCTIONS related to IMPORT handler 'library'
196 */
197
198 int importhandler_createlibrary(){
199 int i;
200 struct ImportHandler *extlib_handler;
201
202 if(importhandler_library!=NULL){
203 /* ERROR_REPORTER_HERE(ASC_PROG_ERR,"Already created"); */
204 return 0;
205 };
206 importhandler_library=ASC_NEW_ARRAY(struct ImportHandler *,IMPORTHANDLER_MAX);
207 for(i=0; i < IMPORTHANDLER_MAX; ++i){
208 importhandler_library[i] = NULL;
209 }
210 /* CONSOLE_DEBUG("ImportHandler library created"); */
211
212 extlib_handler = ASC_NEW(struct ImportHandler);
213 extlib_handler->name ="extlib";
214 extlib_handler->filenamefn = &importhandler_extlib_filename;
215 extlib_handler->importfn = &importhandler_extlib_import;
216 if(importhandler_add(extlib_handler)){
217 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed to create 'extlib' import handler");
218 return 1;
219 }
220
221 return 0;
222 }
223
224 int importhandler_remove(const char *name){
225 if(importhandler_library==NULL)return 2;
226 /* CONSOLE_DEBUG("Removing importhandler '%s'", name); */
227 ERROR_REPORTER_HERE(ASC_PROG_ERR,"%s not implemented",__FUNCTION__);
228 return 1;
229 }
230
231 struct ImportHandler *importhandler_lookup(const char *name){
232 ERROR_REPORTER_HERE(ASC_PROG_ERR,"%s not implemented",__FUNCTION__);
233 return NULL;
234 }
235
236 /** @return 0 on success */
237 int importhandler_destroylibrary(){
238 int i;
239 int err = 0;
240 CONSOLE_DEBUG("Destroying importhandler library...");
241 importhandler_printlibrary(stderr);
242 if(importhandler_library!=NULL){
243 for(i=IMPORTHANDLER_MAX - 1; i >= 0; --i){
244 if(importhandler_library[i]==NULL)continue;
245 err = err | importhandler_remove(importhandler_library[i]->name);
246 }
247 }
248 if(err)ERROR_REPORTER_HERE(ASC_PROG_WARNING,"Failed to destroy importhandler library");
249 return err;
250 }
251
252 /** @return 0 on success */
253 int importhandler_printlibrary(FILE *fp){
254 int i;
255 if(importhandler_library==NULL){
256 fprintf(fp,"# importhandler_printlibrary: empty\n");
257 return 0;
258 }else{
259 fprintf(fp,"# importhandler_printlibrary: start\n");
260 for(i=0; i < IMPORTHANDLER_MAX && importhandler_library[i] != NULL; ++i){
261 fprintf(fp,"%s\n",importhandler_library[i]->name);
262 }
263 fprintf(fp,"# importhandler_printlibrary: end\n");
264 return 0;
265 }
266 }
267
268 int importhandler_printhandler(FILE *fp, struct ImportHandler *handler){
269 ERROR_REPORTER_HERE(ASC_PROG_ERR,"%s not implemented",__FUNCTION__);
270 CONSOLE_DEBUG("NOT IMPLEMENTED");
271 return 1;
272 }
273
274 /*------------------------------------------------------------------------------
275 PATH SEARCH ROUTINES
276 */
277
278 /**
279 A little structure to help with searching for import files
280
281 @see test_importsearch
282 */
283 struct ImportHandlerSearch{
284 char *partialname; /**< for example 'myext' */
285 struct FilePath *relativedir; /**< for example 'path/to' */
286 struct FilePath *foundpath; /**< the complete filepath located, for example '/home/john/path/to/libmyext.so' */
287 struct ImportHandler *handler; /**< pointer to the import handler identified for this file */
288 };
289
290 FilePathTestFn importhandler_search_test;
291
292 /**
293 A FilePath 'test' function for passing to the ospath_searchpath_iterate function.
294 This test function will return a match when an importable file having the
295 required name is present in the fully resolved path.
296
297 @param path the search path component
298 @param userdata will be an ImportHandlerSearch object
299 @return 1 if found
300 */
301 int importhandler_search_test(struct FilePath *path, void *userdata){
302 /* user data = the relative path, plus a place
303 to store the full path when found */
304 FILE *f;
305 char *filename;
306 #ifdef SEARCH_DEBUG
307 char *fullpath;
308 #endif
309 struct ImportHandlerSearch *searchdata;
310 struct FilePath *fp, *fp1, *fp2;
311 int i;
312 ospath_stat_t buf;
313
314 searchdata = (struct ImportHandlerSearch *)userdata;
315
316 #ifdef SEARCH_DEBUG
317 char *pathcomponent;
318 pathcomponent = ospath_str(path); //eg '/home/john'
319 CONSOLE_DEBUG("In directory '%s'...",pathcomponent);
320 ASC_FREE(pathcomponent);
321 #endif
322
323 asc_assert(importhandler_library!=NULL);
324
325 for(i=0; i<IMPORTHANDLER_MAX && importhandler_library[i]!=NULL; ++i){
326
327 filename = (*(importhandler_library[i]->filenamefn))(searchdata->partialname); /* eg 'myext' -> 'libmyext.so' */
328 if(filename==NULL){
329 CONSOLE_DEBUG("Unable to create filename from partialname '%s'",searchdata->partialname);
330 continue;
331 }
332 /* CONSOLE_DEBUG("Filename '%s'",filename); */
333 fp = ospath_new_noclean(filename); /* eg 'libmyext.so' */
334 ASC_FREE(filename);
335 asc_assert(fp!=NULL);
336
337 #ifdef SEARCH_DEBUG
338 fullpath = ospath_str(searchdata->relativedir);
339 CONSOLE_DEBUG("Relative dir is '%s'",fullpath);
340 ASC_FREE(fullpath);
341 #endif
342 fp1 = ospath_concat(path,searchdata->relativedir); /* eg '/home/john/path/to' */
343 asc_assert(fp1!=NULL);
344
345
346 #ifdef SEARCH_DEBUG
347 fullpath = ospath_str(fp1);
348 CONSOLE_DEBUG("Path is '%s'",fullpath);
349 ASC_FREE(fullpath);
350
351 fullpath = ospath_str(fp);
352 CONSOLE_DEBUG("Filename is '%s'",fullpath);
353 ASC_FREE(fullpath);
354 #endif
355
356 fp2 = ospath_concat(fp1,fp); /* eg '/home/john/path/to/libmyext.so' */
357 asc_assert(fp2!=NULL);
358 ospath_free(fp1);
359 ospath_free(fp);
360
361 #ifdef SEARCH_DEBUG
362 fullpath = ospath_str(fp2);
363 CONSOLE_DEBUG("Checking for readable '%s'",fullpath);
364 ASC_FREE(fullpath);
365 #endif
366
367 if(0==ospath_stat(fp2,&buf) && NULL!=(f = ospath_fopen(fp2,"r"))){
368 fclose(f);
369 searchdata->foundpath = fp2;
370 searchdata->handler = importhandler_library[i];
371 return 1; /* success */
372 }
373
374 ospath_free(fp2);
375 }
376 return 0; /* failed */
377 }
378
379 struct FilePath *importhandler_findinpath(const char *partialname
380 , char *defaultpath, char *envv, struct ImportHandler **handler
381 ){
382 struct FilePath *fp, *fp1; /* relative path */
383 struct ImportHandlerSearch searchdata;
384 char *path, *filename;
385 struct FilePath **sp;
386 int i;
387 ospath_stat_t buf;
388 FILE *f;
389
390 fp1 = ospath_new_noclean(partialname); /* eg 'path/to/myext' */
391 if(fp1==NULL){
392 ERROR_REPORTER_HERE(ASC_USER_ERROR,"Invalid partial path '%s'",partialname);
393 return NULL;
394 }
395
396 searchdata.partialname = ospath_getbasefilename(fp1);
397 if(searchdata.partialname==NULL){
398 CONSOLE_DEBUG("Not a filename");
399 ospath_free(fp1);
400 return NULL;
401 }
402
403 searchdata.relativedir = ospath_getdir(fp1);
404 if(searchdata.relativedir ==NULL){
405 ERROR_REPORTER_HERE(ASC_PROG_ERR,"unable to retrieve file dir");
406 ospath_free(fp1);
407 ASC_FREE(searchdata.partialname);
408 return NULL;
409 }
410 ospath_free(fp1);
411
412 searchdata.foundpath = NULL;
413 searchdata.handler = NULL;
414
415 /* first, attempt to open without searching in path */
416
417 for(i=0; i<IMPORTHANDLER_MAX && importhandler_library[i]!=NULL; ++i){
418
419 filename = (*(importhandler_library[i]->filenamefn))(searchdata.partialname); /* eg 'myext' -> 'libmyext.so' */
420 if(filename==NULL){
421 CONSOLE_DEBUG("Unable to create filename from partialname '%s'",searchdata.partialname);
422 continue;
423 }
424
425 fp = ospath_new(filename); /* eg 'libmyext.so' */
426 ASC_FREE(filename);
427 asc_assert(fp!=NULL);
428
429 #ifdef SEARCH_DEBUG
430 path = ospath_str(searchdata.relativedir);
431 CONSOLE_DEBUG("Relative dir is '%s'",path);
432 ASC_FREE(path);
433
434 path = ospath_str(fp);
435 CONSOLE_DEBUG("Filename is '%s'",path);
436 ASC_FREE(path);
437 #endif
438
439 fp1 = ospath_concat(searchdata.relativedir,fp); /* eg '/home/john/path/to/libmyext.so' */
440 asc_assert(fp1!=NULL);
441 ospath_free(fp);
442
443 #ifdef SEARCH_DEBUG
444 path = ospath_str(fp1);
445 CONSOLE_DEBUG("Checking for readable '%s'",path);
446 ASC_FREE(path);
447 #endif
448
449 if(0==ospath_stat(fp1,&buf) && NULL!=(f = ospath_fopen(fp1,"r"))){
450 CONSOLE_DEBUG("FOUND!");
451 fclose(f);
452 ASC_FREE(searchdata.partialname);
453 ospath_free(searchdata.relativedir);
454 *handler = importhandler_library[i];
455 return fp1;
456 }
457 #ifdef SEARCH_DEBUG
458 else{
459 CONSOLE_DEBUG("Not found");
460 }
461 #endif
462
463 ospath_free(fp1);
464 }
465
466 /*-----------------------*/
467
468 path=Asc_GetEnv(envv);
469 if(path==NULL){
470 /* CONSOLE_DEBUG("ENV VAR '%s' NOT FOUND, FALLING BACK TO DEFAULT SEARCH PATH = '%s'",envv,defaultpath); */
471 path=defaultpath;
472 }
473
474 /* CONSOLE_DEBUG("SEARCHPATH IS %s",path); */
475 sp = ospath_searchpath_new(path);
476
477 if(NULL==ospath_searchpath_iterate(sp,&importhandler_search_test,&searchdata)){
478 ospath_free(searchdata.relativedir);
479 ASC_FREE(searchdata.partialname);
480 ospath_searchpath_free(sp);
481 return NULL;
482 }
483
484 ospath_searchpath_free(sp);
485 ASC_FREE(searchdata.partialname);
486 ospath_free(searchdata.relativedir);
487 *handler = searchdata.handler;
488 return searchdata.foundpath;
489 }
490
491 /*------------------------------------------------------------------------------
492 SHARED POINTER TABLE
493 */
494
495 int importhandler_createsharedpointertable(){
496 if(importhandler_sharedpointers==NULL){
497 /* CONSOLE_DEBUG("CREATED SHARED POINTER TABLE"); */
498 importhandler_sharedpointers = CreateTable(31);
499 }
500 return 0;
501 }
502
503 int importhandler_setsharedpointer(const char *key, void *ptr){
504 importhandler_createsharedpointertable();
505 if(key==NULL){
506 ERROR_REPORTER_HERE(ASC_PROG_ERR,"key is NULL");
507 return 1;
508 }
509
510 /* woops! 'AddTableData' does *not* overwrite table entries! */
511 RemoveTableData(importhandler_sharedpointers,(char *)key);
512
513 AddTableData(importhandler_sharedpointers,ptr,key);
514 #ifdef IMPORTHANDLER_VERBOSE
515 CONSOLE_DEBUG("Set shared pointer '%s' to %p",key, ptr);
516 #endif
517 asc_assert(importhandler_getsharedpointer(key)==ptr);
518 return 0;
519 }
520
521 void *importhandler_getsharedpointer(const char *key){
522 importhandler_createsharedpointertable();
523 if(key==NULL){
524 ERROR_REPORTER_HERE(ASC_PROG_ERR,"key is NULL");
525 return NULL;
526 }
527 return LookupTableData(importhandler_sharedpointers,key);
528 }

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22