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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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