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

Contents of /trunk/ascend/compiler/importhandler.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2353 - (show annotations) (download) (as text)
Sat Jan 8 11:21:09 2011 UTC (11 years, 5 months ago) by jpye
File MIME type: text/x-csrc
File size: 17028 byte(s)
fixed bug in destruction of importhandler_library. More work still to be done there.
Improved parser message for failed IMPORT.
1 /* ASCEND modelling environment
2 Copyright (C) 2006, 2010 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 <ascend/utilities/config.h>
30 #include <ascend/utilities/error.h>
31 #include <ascend/utilities/ascDynaLoad.h>
32 #include <ascend/general/panic.h>
33 #include <ascend/utilities/ascEnvVar.h>
34 #include <ascend/general/table.h>
35
36 #include <string.h>
37
38 /* #define SEARCH_DEBUG */
39 /* #define FIND_DEBUG */
40 /* #define IMPORTHANDLER_VERBOSE */
41 /* #define IMPORT_DEBUG */
42
43 /*
44 Maximum number of importhandlers possible in one session. Hard to imagine
45 that you would want more than this.
46 */
47 #define IMPORTHANDLER_MAX 10
48
49 /**
50 List of import handlers currently in effect. @TODO this shouldn't be a global,
51 but unfortunately such globals are 'The ASCEND Way'.
52 */
53 struct ImportHandler **importhandler_library=NULL;
54
55 /**
56 Table of registered pointers for use in passing GUI data out to external scripts.
57 */
58 struct Table *importhandler_sharedpointers=NULL;
59
60 ASC_DLLSPEC int importhandler_add(struct ImportHandler *handler){
61 int i;
62 if(handler==NULL){
63 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Handler is NULL");
64 return 2;
65 }
66 if(importhandler_library == NULL){
67 importhandler_createlibrary();
68 }
69 for(i=0; i< IMPORTHANDLER_MAX; ++i){
70 if(importhandler_library[i] == NULL)break;
71 if(importhandler_library[i]->name == handler->name){
72 ERROR_REPORTER_HERE(ASC_USER_NOTE,"Handler already loaded");
73 return 0;
74 }
75 }
76 if(i==IMPORTHANDLER_MAX){
77 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Too many import handlers register (IMPORTHANDLER_MAX=%d)",IMPORTHANDLER_MAX);
78 return 1;
79 }
80 importhandler_library[i] = handler;
81 #ifdef IMPORTHANDLER_VERBOSE
82 ERROR_REPORTER_HERE(ASC_USER_NOTE,"New import hander '%s' added",handler->name);
83 #endif
84 return 0;
85 }
86
87 /* Function to attempt import of an external script
88 @param partialname Name of the external script (without extension), relative to PATH.
89 @param defaultpath Default value of file search PATH. Is trumped by value of pathenvvar if present in environment.
90 @param pathenvvar Environment variable containing the user's preferred file search path value.
91 @return 0 on success
92 */
93 int importhandler_attemptimport(const char *partialname,const char *defaultpath, const char *pathenvvar){
94 ERROR_REPORTER_HERE(ASC_PROG_ERR,"%s not implemented",__FUNCTION__);
95 return 1;
96 }
97
98 /*------------------------------------------------------------------------------
99 DEFAULT IMPORT HANDLER FOR DLL/SO FILES
100 */
101
102 /**
103 Create a filename for an external library (DLL/SO) based on a
104 partial filename.
105
106 @param partialname The partial filename (eg 'mylib')
107 @return Complete filename (eg 'libmylib.so' or 'mylib.dlll', etc)
108 */
109 char *importhandler_extlib_filename(const char *partialname){
110 char *buffer;
111 buffer = ASC_NEW_ARRAY(char,PATH_MAX);
112
113 #if defined(ASC_EXTLIBSUFFIX) && defined(ASC_EXTLIBPREFIX)
114 /*
115 this is the preferred operation: SCons reports what the local system
116 uses as its shared library file extension.
117 */
118 snprintf(buffer,PATH_MAX,"%s%s%s",ASC_EXTLIBPREFIX,partialname,ASC_EXTLIBSUFFIX);
119 #else
120 #ifdef __GNUC__
121 # warning "You should be using Use ASC_EXTLIBPREFIX and ASC_EXTLIBSUFFIX!"
122 #endif
123 /**
124 @DEPRECATED
125
126 If we don't have ASC_EXTLIB-SUFFIX and -PREFIX then we can do some
127 system-specific stuff here, but it's not as general.
128 */
129 # ifdef __WIN32__
130 snprintf(buffer,PATH_MAX,"%s.dll",partialname);
131 # elif defined(linux)
132 snprintf(buffer,PATH_MAX,"lib%s.so",partialname); /* changed from .o to .so -- JP */
133 # elif defined(sun) || defined(solaris)
134 snprintf(buffer,PATH_MAX,"%s.so.1.0",partialname);
135 # elif defined(__hpux)
136 snprintf(buffer,PATH_MAX,"%s.sl",partialname);
137 # elif defined(_SGI_SOURCE)
138 snprintf(buffer,PATH_MAX,"%s.so",partialname);
139 # else
140 # error "Unknown system type (please define ASC_EXTLIBSUFFIX and ASC_EXTLIBPREFIX)"
141 # endif
142 #endif
143
144 return buffer;
145 }
146
147 /**
148 Perform the actual importing of an external DLL/SO in to ASCEND. Can assume
149 that the file exists and is readable.
150
151 @param fp Location of DLL/SO file
152 @param initfunc Name of registration function, preferably NULL (so that ASCEND automatically determines it)
153 @param partialpath as specified in 'IMPORT' statement, for creation of auto_initfunc name
154 @return 0 on success
155 */
156 int importhandler_extlib_import(const struct FilePath *fp,const char *initfunc,const char *partialpath){
157
158 struct FilePath *fp1;
159 char *stem;
160 char *path;
161 char auto_initfunc[PATH_MAX];
162 int result;
163
164 path = ospath_str(fp);
165 if(path==NULL){
166 ERROR_REPORTER_HERE(ASC_PROG_ERR,"File path is NULL");
167 return 1;
168 }
169 #ifdef IMPORT_DEBUG
170 CONSOLE_DEBUG("Importing extlib with path '%s'",path);
171 #endif
172
173 if(initfunc==NULL){
174 fp1 = ospath_new(partialpath);
175 stem = ospath_getbasefilename(fp1);
176 strncpy(auto_initfunc,stem,PATH_MAX);
177 ospath_free(fp1);
178 ASC_FREE(stem);
179
180 strncat(auto_initfunc,"_register",PATH_MAX-strlen(auto_initfunc));
181 /* CONSOLE_DEBUG("Created auto-initfunc name '%s'",auto_initfunc); */
182 result = Asc_DynamicLoad(path,auto_initfunc);
183 }else{
184 result = Asc_DynamicLoad(path,initfunc);
185 }
186
187 #ifdef IMPORT_DEBUG
188 if(result){
189 CONSOLE_DEBUG("FAILED TO IMPORT '%s' (error %d)",partialpath,result);
190 }else{
191 if(initfunc==NULL){
192 CONSOLE_DEBUG("'%s' OK (%s)",auto_initfunc,path);
193 }else{
194 CONSOLE_DEBUG("'%s' OK (explicitly named, got file '%s')",initfunc,path);
195 }
196 }
197 #endif
198
199 ASC_FREE(path);
200 return result;
201 }
202
203 /*------------------------------------------------------------------------------
204 LIST-BASED FUNCTIONS related to IMPORT handler 'library'
205 */
206
207 int importhandler_createlibrary(){
208 int i;
209 struct ImportHandler *extlib_handler;
210
211 if(importhandler_library!=NULL){
212 /* ERROR_REPORTER_HERE(ASC_PROG_ERR,"Already created"); */
213 return 0;
214 };
215 importhandler_library=ASC_NEW_ARRAY(struct ImportHandler *,IMPORTHANDLER_MAX);
216 for(i=0; i < IMPORTHANDLER_MAX; ++i){
217 importhandler_library[i] = NULL;
218 }
219 /* CONSOLE_DEBUG("ImportHandler library created"); */
220
221 extlib_handler = ASC_NEW(struct ImportHandler);
222 extlib_handler->name ="extlib";
223 extlib_handler->filenamefn = &importhandler_extlib_filename;
224 extlib_handler->importfn = &importhandler_extlib_import;
225 extlib_handler->destroyfn = NULL;
226 if(importhandler_add(extlib_handler)){
227 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed to create 'extlib' import handler");
228 return 1;
229 }
230
231 return 0;
232 }
233
234 int importhandler_destroy(struct ImportHandler *handler){
235 int res = 0;
236 if(handler->destroyfn){
237 res = (*(handler->destroyfn))(handler);
238 }/* else: nothing inside needs destroying */
239 if(!res)ASC_FREE(handler);
240 return res;
241 }
242
243 struct ImportHandler *importhandler_lookup(const char *name){
244 int i;
245 for(i=0; i < IMPORTHANDLER_MAX && importhandler_library[i] != NULL; ++i){
246 if(importhandler_library[i]->name
247 && 0==strcmp(name,importhandler_library[i]->name)
248 ){
249 return importhandler_library[i];
250 }
251 }
252 return NULL;
253 }
254
255 /** @return 0 on success */
256 int importhandler_destroylibrary(){
257 int i;
258 int err = 0, thiserr;
259 #ifdef IMPORT_DEBUG
260 CONSOLE_DEBUG("Destroying importhandler library...");
261 #endif
262 ///importhandler_printlibrary(stderr);
263 if(importhandler_library!=NULL){
264 for(i=IMPORTHANDLER_MAX - 1; i >= 0; --i){
265 if(importhandler_library[i]==NULL)continue;
266 thiserr = importhandler_destroy(importhandler_library[i]);
267 if(!thiserr){
268 importhandler_library[i] = NULL;
269 #ifdef IMPORT_DEBUG
270 CONSOLE_DEBUG("Destroyed import handler");
271 #endif
272 }
273 err = err | thiserr;
274 }
275 if(!err){
276 ASC_FREE(importhandler_library);
277 importhandler_library = NULL;
278 }
279 }
280 if(err)ERROR_REPORTER_HERE(ASC_PROG_WARNING,"Failed to destroy importhandler library");
281 return err;
282 }
283
284 /** @return 0 on success */
285 int importhandler_printlibrary(FILE *fp){
286 int i;
287 if(importhandler_library==NULL){
288 fprintf(fp,"# importhandler_printlibrary: empty\n");
289 return 0;
290 }else{
291 fprintf(fp,"# importhandler_printlibrary: start\n");
292 for(i=0; i < IMPORTHANDLER_MAX && importhandler_library[i] != NULL; ++i){
293 fprintf(fp,"%s\n",importhandler_library[i]->name);
294 }
295 fprintf(fp,"# importhandler_printlibrary: end\n");
296 return 0;
297 }
298 }
299
300 int importhandler_printhandler(FILE *fp, struct ImportHandler *handler){
301 ERROR_REPORTER_HERE(ASC_PROG_ERR,"%s not implemented",__FUNCTION__);
302 CONSOLE_DEBUG("NOT IMPLEMENTED");
303 return 1;
304 }
305
306 /*------------------------------------------------------------------------------
307 PATH SEARCH ROUTINES
308 */
309
310 /**
311 A little structure to help with searching for import files
312
313 @see test_importsearch
314 */
315 struct ImportHandlerSearch{
316 char *partialname; /**< for example 'myext' */
317 struct FilePath *relativedir; /**< for example 'path/to' */
318 struct FilePath *foundpath; /**< the complete filepath located, for example '/home/john/path/to/libmyext.so' */
319 struct ImportHandler *handler; /**< pointer to the import handler identified for this file */
320 };
321
322 FilePathTestFn importhandler_search_test;
323
324 /**
325 A FilePath 'test' function for passing to the ospath_searchpath_iterate function.
326 This test function will return a match when an importable file having the
327 required name is present in the fully resolved path.
328
329 @param path the search path component
330 @param userdata will be an ImportHandlerSearch object
331 @return 1 if found
332 */
333 int importhandler_search_test(struct FilePath *path, void *userdata){
334 /* user data = the relative path, plus a place
335 to store the full path when found */
336 FILE *f;
337 char *filename;
338 #ifdef SEARCH_DEBUG
339 char *fullpath;
340 #endif
341 struct ImportHandlerSearch *searchdata;
342 struct FilePath *fp, *fp1, *fp2;
343 int i;
344 ospath_stat_t buf;
345
346 searchdata = (struct ImportHandlerSearch *)userdata;
347
348 #ifdef SEARCH_DEBUG
349 char *pathcomponent;
350 pathcomponent = ospath_str(path); //eg '/home/john'
351 CONSOLE_DEBUG("In directory '%s'...",pathcomponent);
352 ASC_FREE(pathcomponent);
353 #endif
354
355 asc_assert(importhandler_library!=NULL);
356
357 for(i=0; i<IMPORTHANDLER_MAX && importhandler_library[i]!=NULL; ++i){
358
359 filename = (*(importhandler_library[i]->filenamefn))(searchdata->partialname); /* eg 'myext' -> 'libmyext.so' */
360 if(filename==NULL){
361 #ifdef SEARCH_DEBUG
362 CONSOLE_DEBUG("Unable to create filename from partialname '%s'",searchdata->partialname);
363 #endif
364 continue;
365 }
366 #ifdef SEARCH_DEBUG
367 CONSOLE_DEBUG("Filename '%s'",filename);
368 #endif
369 fp = ospath_new_noclean(filename); /* eg 'libmyext.so' */
370 ASC_FREE(filename);
371 asc_assert(fp!=NULL);
372
373 #ifdef SEARCH_DEBUG
374 fullpath = ospath_str(searchdata->relativedir);
375 CONSOLE_DEBUG("Relative dir is '%s'",fullpath);
376 ASC_FREE(fullpath);
377 #endif
378 fp1 = ospath_concat(path,searchdata->relativedir); /* eg '/home/john/path/to' */
379 asc_assert(fp1!=NULL);
380
381
382 #ifdef SEARCH_DEBUG
383 fullpath = ospath_str(fp1);
384 CONSOLE_DEBUG("Path is '%s'",fullpath);
385 ASC_FREE(fullpath);
386
387 fullpath = ospath_str(fp);
388 CONSOLE_DEBUG("Filename is '%s'",fullpath);
389 ASC_FREE(fullpath);
390 #endif
391
392 fp2 = ospath_concat(fp1,fp); /* eg '/home/john/path/to/libmyext.so' */
393 asc_assert(fp2!=NULL);
394 ospath_free(fp1);
395 ospath_free(fp);
396
397 #ifdef SEARCH_DEBUG
398 fullpath = ospath_str(fp2);
399 CONSOLE_DEBUG("Checking for readable '%s'",fullpath);
400 ASC_FREE(fullpath);
401 #endif
402
403 if(0==ospath_stat(fp2,&buf) && NULL!=(f = ospath_fopen(fp2,"r"))){
404 fclose(f);
405 searchdata->foundpath = fp2;
406 searchdata->handler = importhandler_library[i];
407 return 1; /* success */
408 }
409
410 ospath_free(fp2);
411 }
412 return 0; /* failed */
413 }
414
415 struct FilePath *importhandler_findinpath(const char *partialname
416 , const char *defaultpath, char *envv, struct ImportHandler **handler
417 ){
418 struct FilePath *fp, *fp1; /* relative path */
419 struct ImportHandlerSearch searchdata;
420 char *path, *filename;
421 struct FilePath **sp;
422 int i;
423 ospath_stat_t buf;
424 FILE *f;
425 const char *epath;
426 char *epathmem = NULL;
427
428 fp1 = ospath_new_noclean(partialname); /* eg 'path/to/myext' */
429 if(fp1==NULL){
430 ERROR_REPORTER_HERE(ASC_USER_ERROR,"Invalid partial path '%s'",partialname);
431 return NULL;
432 }
433
434 searchdata.partialname = ospath_getbasefilename(fp1);
435 if(searchdata.partialname==NULL){
436 #ifdef FIND_DEBUG
437 CONSOLE_DEBUG("Not a filename");
438 #endif
439 ospath_free(fp1);
440 return NULL;
441 }
442
443 searchdata.relativedir = ospath_getdir(fp1);
444 if(searchdata.relativedir ==NULL){
445 ERROR_REPORTER_HERE(ASC_PROG_ERR,"unable to retrieve file dir");
446 ospath_free(fp1);
447 ASC_FREE(searchdata.partialname);
448 return NULL;
449 }
450 ospath_free(fp1);
451
452 searchdata.foundpath = NULL;
453 searchdata.handler = NULL;
454
455 /* first, attempt to open without searching in path */
456
457 #ifdef FIND_DEBUG
458 CONSOLE_DEBUG("SEARCHING RELATIVE TO CURRENT DIRECTORY");
459 #endif
460
461 for(i=0; i<IMPORTHANDLER_MAX && importhandler_library[i]!=NULL; ++i){
462
463 filename = (*(importhandler_library[i]->filenamefn))(searchdata.partialname); /* eg 'myext' -> 'libmyext.so' */
464 if(filename==NULL){
465 #ifdef FIND_DEBUG
466 CONSOLE_DEBUG("Unable to create filename from partialname '%s'",searchdata.partialname);
467 #endif
468 continue;
469 }
470
471 fp = ospath_new(filename); /* eg 'libmyext.so' */
472 ASC_FREE(filename);
473 asc_assert(fp!=NULL);
474
475 path = ospath_str(searchdata.relativedir);
476 if(strlen(path)==0){
477 #ifdef FIND_DEBUG
478 CONSOLE_DEBUG("ADDING '.' AT START OF EMPTY RELATIVE PATH");
479 #endif
480 ospath_free(searchdata.relativedir);
481 searchdata.relativedir = ospath_new_noclean(".");
482 ASC_FREE(path);
483 path = ospath_str(searchdata.relativedir);
484 }
485 #ifdef FIND_DEBUG
486 CONSOLE_DEBUG("Relative dir is '%s'",path);
487 #endif
488 ASC_FREE(path);
489
490 #ifdef FIND_DEBUG
491 path = ospath_str(fp);
492 CONSOLE_DEBUG("Filename is '%s'",path);
493 ASC_FREE(path);
494 #endif
495
496 fp1 = ospath_concat(searchdata.relativedir,fp); /* eg '/home/john/path/to/libmyext.so' */
497 asc_assert(fp1!=NULL);
498 ospath_free(fp);
499
500 #ifdef FIND_DEBUG
501 path = ospath_str(fp1);
502 CONSOLE_DEBUG("Checking for readable '%s'",path);
503 ASC_FREE(path);
504 #endif
505
506 if(0==ospath_stat(fp1,&buf) && NULL!=(f = ospath_fopen(fp1,"r"))){
507 #ifdef FIND_DEBUG
508 CONSOLE_DEBUG("Found in current directory!");
509 #endif
510 fclose(f);
511 ASC_FREE(searchdata.partialname);
512 ospath_free(searchdata.relativedir);
513 *handler = importhandler_library[i];
514 return fp1;
515 }
516 #ifdef FIND_DEBUG
517 else{
518 CONSOLE_DEBUG("Not found");
519 }
520 #endif
521
522 ospath_free(fp1);
523 }
524
525 /*-----------------------*/
526
527 #ifdef FIND_DEBUG
528 CONSOLE_DEBUG("SEARCHING ACCORDING TO ENV VAR $%s",envv);
529 #endif
530
531 epath = defaultpath;
532 epathmem=Asc_GetEnv(envv);
533 if(epathmem){
534 epath = epathmem;
535 #ifdef FIND_DEBUG
536 }else{
537 CONSOLE_DEBUG("ENV VAR '%s' NOT FOUND, FALLING BACK TO DEFAULT SEARCH PATH = '%s'",envv,defaultpath);
538 #endif
539 }
540
541 #ifdef FIND_DEBUG
542 CONSOLE_DEBUG("SEARCHPATH IS %s",epath);
543 #endif
544 sp = ospath_searchpath_new(epath);
545
546 if(NULL==ospath_searchpath_iterate(sp,&importhandler_search_test,&searchdata)){
547 #ifdef FIND_DEBUG
548 CONSOLE_DEBUG("Import not found in searchpath");
549 #endif
550 ospath_free(searchdata.relativedir);
551 ASC_FREE(searchdata.partialname);
552 ospath_searchpath_free(sp);
553 if(epathmem)ASC_FREE(epathmem);
554 return NULL;
555 }
556
557 #ifdef FIND_DEBUG
558 CONSOLE_DEBUG("Found in searchpath :-)");
559 #endif
560
561 ospath_searchpath_free(sp);
562 ASC_FREE(searchdata.partialname);
563 if(epathmem)ASC_FREE(epathmem);
564 ospath_free(searchdata.relativedir);
565 *handler = searchdata.handler;
566 return searchdata.foundpath;
567 }
568
569 /*------------------------------------------------------------------------------
570 SHARED POINTER TABLE
571 */
572
573 int importhandler_createsharedpointertable(){
574 if(importhandler_sharedpointers==NULL){
575 /* CONSOLE_DEBUG("CREATED SHARED POINTER TABLE"); */
576 importhandler_sharedpointers = CreateTable(31);
577 }
578 return 0;
579 }
580
581 int importhandler_setsharedpointer(const char *key, void *ptr){
582 importhandler_createsharedpointertable();
583 if(key==NULL){
584 ERROR_REPORTER_HERE(ASC_PROG_ERR,"key is NULL");
585 return 1;
586 }
587
588 /* woops! 'AddTableData' does *not* overwrite table entries! */
589 RemoveTableData(importhandler_sharedpointers,(char *)key);
590
591 AddTableData(importhandler_sharedpointers,ptr,key);
592 #ifdef IMPORTHANDLER_VERBOSE
593 CONSOLE_DEBUG("Set shared pointer '%s' to %p",key, ptr);
594 #endif
595 asc_assert(importhandler_getsharedpointer(key)==ptr);
596 return 0;
597 }
598
599 void *importhandler_getsharedpointer(const char *key){
600 importhandler_createsharedpointertable();
601 if(key==NULL){
602 ERROR_REPORTER_HERE(ASC_PROG_ERR,"key is NULL");
603 return NULL;
604 }
605 return LookupTableData(importhandler_sharedpointers,key);
606 }

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