xref: /petsc/src/sys/dll/reg.c (revision 6d75e2106b7ce71d78ffad317d596124b1823eef)
1 
2 /*
3     Provides a general mechanism to allow one to register new routines in
4     dynamic libraries for many of the PETSc objects (including, e.g., KSP and PC).
5 */
6 #include <petscsys.h>           /*I "petscsys.h" I*/
7 
8 #undef __FUNCT__
9 #define __FUNCT__ "PetscFListGetPathAndFunction"
10 PetscErrorCode  PetscFListGetPathAndFunction(const char name[],char *path[],char *function[])
11 {
12   PetscErrorCode ierr;
13   char           work[PETSC_MAX_PATH_LEN],*lfunction;
14 
15   PetscFunctionBegin;
16   ierr = PetscStrncpy(work,name,sizeof(work));CHKERRQ(ierr);
17   work[sizeof(work) - 1] = 0;
18   ierr = PetscStrchr(work,':',&lfunction);CHKERRQ(ierr);
19   if (lfunction != work && lfunction && lfunction[1] != ':') {
20     lfunction[0] = 0;
21     ierr = PetscStrallocpy(work,path);CHKERRQ(ierr);
22     ierr = PetscStrallocpy(lfunction+1,function);CHKERRQ(ierr);
23   } else {
24     *path = 0;
25     ierr = PetscStrallocpy(name,function);CHKERRQ(ierr);
26   }
27   PetscFunctionReturn(0);
28 }
29 
30 /*
31     This is the default list used by PETSc with the PetscDLLibrary register routines
32 */
33 PetscDLLibrary PetscDLLibrariesLoaded = 0;
34 
35 #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
36 
37 #undef __FUNCT__
38 #define __FUNCT__ "PetscLoadDynamicLibrary"
39 static PetscErrorCode  PetscLoadDynamicLibrary(const char *name,PetscBool  *found)
40 {
41   char           libs[PETSC_MAX_PATH_LEN],dlib[PETSC_MAX_PATH_LEN];
42   PetscErrorCode ierr;
43 
44   PetscFunctionBegin;
45   ierr = PetscStrcpy(libs,"${PETSC_LIB_DIR}/libpetsc");CHKERRQ(ierr);
46   ierr = PetscStrcat(libs,name);CHKERRQ(ierr);
47   ierr = PetscDLLibraryRetrieve(PETSC_COMM_WORLD,libs,dlib,1024,found);CHKERRQ(ierr);
48   if (*found) {
49     ierr = PetscDLLibraryAppend(PETSC_COMM_WORLD,&PetscDLLibrariesLoaded,dlib);CHKERRQ(ierr);
50   } else {
51     ierr = PetscStrcpy(libs,"${PETSC_DIR}/${PETSC_ARCH}/lib/libpetsc");CHKERRQ(ierr);
52     ierr = PetscStrcat(libs,name);CHKERRQ(ierr);
53     ierr = PetscDLLibraryRetrieve(PETSC_COMM_WORLD,libs,dlib,1024,found);CHKERRQ(ierr);
54     if (*found) {
55       ierr = PetscDLLibraryAppend(PETSC_COMM_WORLD,&PetscDLLibrariesLoaded,dlib);CHKERRQ(ierr);
56     }
57   }
58   PetscFunctionReturn(0);
59 }
60 
61 #endif
62 
63 #undef __FUNCT__
64 #define __FUNCT__ "PetscInitialize_DynamicLibraries"
65 /*
66     PetscInitialize_DynamicLibraries - Adds the default dynamic link libraries to the
67     search path.
68 */
69 PetscErrorCode  PetscInitialize_DynamicLibraries(void)
70 {
71   char           *libname[32];
72   PetscErrorCode ierr;
73   PetscInt       nmax,i;
74 #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
75   PetscBool      found;
76 #endif
77 
78   PetscFunctionBegin;
79   nmax = 32;
80   ierr = PetscOptionsGetStringArray(PETSC_NULL,"-dll_prepend",libname,&nmax,PETSC_NULL);CHKERRQ(ierr);
81   for (i=0; i<nmax; i++) {
82     ierr = PetscDLLibraryPrepend(PETSC_COMM_WORLD,&PetscDLLibrariesLoaded,libname[i]);CHKERRQ(ierr);
83     ierr = PetscFree(libname[i]);CHKERRQ(ierr);
84   }
85 
86 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
87   /*
88       This just initializes the most basic PETSc stuff.
89 
90     The classes, from PetscDraw to PetscTS, are initialized the first
91     time an XXCreate() is called.
92   */
93   ierr = PetscSysInitializePackage(PETSC_NULL);CHKERRQ(ierr);
94 #else
95 #if defined(PETSC_USE_SINGLE_LIBRARY)
96   ierr = PetscLoadDynamicLibrary("",&found);CHKERRQ(ierr);
97   if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate PETSc dynamic library \n You cannot move the dynamic libraries!");
98 #else
99   ierr = PetscLoadDynamicLibrary("sys",&found);CHKERRQ(ierr);
100   if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate PETSc dynamic library \n You cannot move the dynamic libraries!");
101   ierr = PetscLoadDynamicLibrary("vec",&found);CHKERRQ(ierr);
102   if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate PETSc Vec dynamic library \n You cannot move the dynamic libraries!");
103   ierr = PetscLoadDynamicLibrary("mat",&found);CHKERRQ(ierr);
104   if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate PETSc Mat dynamic library \n You cannot move the dynamic libraries!");
105   ierr = PetscLoadDynamicLibrary("dm",&found);CHKERRQ(ierr);
106   if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate PETSc DM dynamic library \n You cannot move the dynamic libraries!");
107   ierr = PetscLoadDynamicLibrary("characteristic",&found);CHKERRQ(ierr);
108   if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate PETSc Characteristic dynamic library \n You cannot move the dynamic libraries!");
109   ierr = PetscLoadDynamicLibrary("ksp",&found);CHKERRQ(ierr);
110   if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate PETSc KSP dynamic library \n You cannot move the dynamic libraries!");
111   ierr = PetscLoadDynamicLibrary("snes",&found);CHKERRQ(ierr);
112   if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate PETSc SNES dynamic library \n You cannot move the dynamic libraries!");
113   ierr = PetscLoadDynamicLibrary("ts",&found);CHKERRQ(ierr);
114   if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate PETSc TS dynamic library \n You cannot move the dynamic libraries!");
115 #endif
116 
117   ierr = PetscLoadDynamicLibrary("mesh",&found);CHKERRQ(ierr);
118   ierr = PetscLoadDynamicLibrary("contrib",&found);CHKERRQ(ierr);
119 #endif
120 
121   nmax = 32;
122   ierr = PetscOptionsGetStringArray(PETSC_NULL,"-dll_append",libname,&nmax,PETSC_NULL);CHKERRQ(ierr);
123   for (i=0; i<nmax; i++) {
124     ierr = PetscDLLibraryAppend(PETSC_COMM_WORLD,&PetscDLLibrariesLoaded,libname[i]);CHKERRQ(ierr);
125     ierr = PetscFree(libname[i]);CHKERRQ(ierr);
126   }
127 
128   PetscFunctionReturn(0);
129 }
130 
131 #undef __FUNCT__
132 #define __FUNCT__ "PetscFinalize_DynamicLibraries"
133 /*
134      PetscFinalize_DynamicLibraries - Closes the opened dynamic libraries.
135 */
136 PetscErrorCode PetscFinalize_DynamicLibraries(void)
137 {
138   PetscErrorCode ierr;
139   PetscBool      flg = PETSC_FALSE;
140 
141   PetscFunctionBegin;
142   ierr = PetscOptionsGetBool(PETSC_NULL,"-dll_view",&flg,PETSC_NULL);CHKERRQ(ierr);
143   if (flg) { ierr = PetscDLLibraryPrintPath(PetscDLLibrariesLoaded);CHKERRQ(ierr); }
144   ierr = PetscDLLibraryClose(PetscDLLibrariesLoaded);CHKERRQ(ierr);
145   PetscDLLibrariesLoaded = 0;
146   PetscFunctionReturn(0);
147 }
148 
149 
150 
151 /* ------------------------------------------------------------------------------*/
152 struct _n_PetscFList {
153   void        (*routine)(void);   /* the routine */
154   char        *path;              /* path of link library containing routine */
155   char        *name;              /* string to identify routine */
156   char        *rname;             /* routine name in dynamic library */
157   PetscFList  next;               /* next pointer */
158   PetscFList  next_list;          /* used to maintain list of all lists for freeing */
159 };
160 
161 /*
162      Keep a linked list of PetscFLists so that we can destroy all the left-over ones.
163 */
164 static PetscFList   dlallhead = 0;
165 
166 #undef __FUNCT__
167 #define __FUNCT__ "PetscFListAdd"
168 /*@C
169    PetscFListAdd - Given a routine and a string id, saves that routine in the
170    specified registry.
171 
172      Formally Collective on MPI_Comm
173 
174    Input Parameters:
175 +  comm  - the comm where this exists (currently not used)
176 .  fl    - pointer registry
177 .  name  - string to identify routine
178 .  rname - routine name in dynamic library
179 -  fnc   - function pointer (optional if using dynamic libraries)
180 
181    Notes:
182    To remove a registered routine, pass in a PETSC_NULL rname and fnc().
183 
184    Users who wish to register new classes for use by a particular PETSc
185    component (e.g., SNES) should generally call the registration routine
186    for that particular component (e.g., SNESRegisterDynamic()) instead of
187    calling PetscFListAdd() directly.
188 
189    ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, or ${any environmental variable}
190   occuring in pathname will be replaced with appropriate values.
191 
192    Level: developer
193 
194 .seealso: PetscFListDestroy(), SNESRegisterDynamic(), KSPRegisterDynamic(),
195           PCRegisterDynamic(), TSRegisterDynamic(), PetscFList
196 @*/
197 PetscErrorCode  PetscFListAdd(MPI_Comm comm,PetscFList *fl,const char name[],const char rname[],void (*fnc)(void))
198 {
199   PetscFList     entry,ne;
200   PetscErrorCode ierr;
201   char           *fpath,*fname;
202 
203   PetscFunctionBegin;
204   if (!*fl) {
205     ierr           = PetscNew(struct _n_PetscFList,&entry);CHKERRQ(ierr);
206     ierr           = PetscStrallocpy(name,&entry->name);CHKERRQ(ierr);
207     ierr           = PetscFListGetPathAndFunction(rname,&fpath,&fname);CHKERRQ(ierr);
208     entry->path    = fpath;
209     entry->rname   = fname;
210     entry->routine = fnc;
211     entry->next    = 0;
212     *fl = entry;
213 
214     /* add this new list to list of all lists */
215     if (!dlallhead) {
216       dlallhead        = *fl;
217       (*fl)->next_list = 0;
218     } else {
219       ne               = dlallhead;
220       dlallhead        = *fl;
221       (*fl)->next_list = ne;
222     }
223   } else {
224     /* search list to see if it is already there */
225     ne = *fl;
226     while (ne) {
227       PetscBool  founddup;
228 
229       ierr = PetscStrcmp(ne->name,name,&founddup);CHKERRQ(ierr);
230       if (founddup) { /* found duplicate */
231         ierr = PetscFListGetPathAndFunction(rname,&fpath,&fname);CHKERRQ(ierr);
232         ierr = PetscFree(ne->path);CHKERRQ(ierr);
233         ierr = PetscFree(ne->rname);CHKERRQ(ierr);
234         ne->path    = fpath;
235         ne->rname   = fname;
236         ne->routine = fnc;
237         PetscFunctionReturn(0);
238       }
239       if (ne->next) ne = ne->next; else break;
240     }
241     /* create new entry and add to end of list */
242     ierr           = PetscNew(struct _n_PetscFList,&entry);CHKERRQ(ierr);
243     ierr           = PetscStrallocpy(name,&entry->name);CHKERRQ(ierr);
244     ierr           = PetscFListGetPathAndFunction(rname,&fpath,&fname);CHKERRQ(ierr);
245     entry->path    = fpath;
246     entry->rname   = fname;
247     entry->routine = fnc;
248     entry->next    = 0;
249     ne->next       = entry;
250   }
251   PetscFunctionReturn(0);
252 }
253 
254 #undef __FUNCT__
255 #define __FUNCT__ "PetscFListDestroy"
256 /*@
257     PetscFListDestroy - Destroys a list of registered routines.
258 
259     Input Parameter:
260 .   fl  - pointer to list
261 
262     Level: developer
263 
264 .seealso: PetscFListAddDynamic(), PetscFList
265 @*/
266 PetscErrorCode  PetscFListDestroy(PetscFList *fl)
267 {
268   PetscFList     next,entry,tmp = dlallhead;
269   PetscErrorCode ierr;
270 
271   PetscFunctionBegin;
272   if (!*fl) PetscFunctionReturn(0);
273   if (!dlallhead) PetscFunctionReturn(0);
274 
275   /*
276        Remove this entry from the master DL list (if it is in it)
277   */
278   if (dlallhead == *fl) {
279     if (dlallhead->next_list) {
280       dlallhead = dlallhead->next_list;
281     } else {
282       dlallhead = 0;
283     }
284   } else {
285     while (tmp->next_list != *fl) {
286       tmp = tmp->next_list;
287       if (!tmp->next_list) break;
288     }
289     if (tmp->next_list) tmp->next_list = tmp->next_list->next_list;
290   }
291 
292   /* free this list */
293   entry = *fl;
294   while (entry) {
295     next = entry->next;
296     ierr = PetscFree(entry->path);CHKERRQ(ierr);
297     ierr = PetscFree(entry->name);CHKERRQ(ierr);
298     ierr = PetscFree(entry->rname);CHKERRQ(ierr);
299     ierr = PetscFree(entry);CHKERRQ(ierr);
300     entry = next;
301   }
302   *fl = 0;
303   PetscFunctionReturn(0);
304 }
305 
306 /*
307    Destroys all the function lists that anyone has every registered, such as KSPList, VecList, etc.
308 */
309 #undef __FUNCT__
310 #define __FUNCT__ "PetscFListDestroyAll"
311 PetscErrorCode  PetscFListDestroyAll(void)
312 {
313   PetscFList     tmp2,tmp1 = dlallhead;
314   PetscErrorCode ierr;
315 
316   PetscFunctionBegin;
317   while (tmp1) {
318     tmp2 = tmp1->next_list;
319     ierr = PetscFListDestroy(&tmp1);CHKERRQ(ierr);
320     tmp1 = tmp2;
321   }
322   dlallhead = 0;
323   PetscFunctionReturn(0);
324 }
325 
326 #undef __FUNCT__
327 #define __FUNCT__ "PetscFListFind"
328 /*@C
329     PetscFListFind - Given a name, finds the matching routine.
330 
331     Input Parameters:
332 +   fl   - pointer to list
333 .   comm - processors looking for routine
334 .   name - name string
335 -   searchlibraries - if not found in the list then search the dynamic libraries and executable for the symbol
336 
337     Output Parameters:
338 .   r - the routine
339 
340     Level: developer
341 
342 .seealso: PetscFListAddDynamic(), PetscFList
343 @*/
344 PetscErrorCode  PetscFListFind(MPI_Comm comm,PetscFList fl,const char name[],PetscBool searchlibraries,void (**r)(void))
345 {
346   PetscFList     entry = fl;
347   PetscErrorCode ierr;
348   char           *function,*path;
349   PetscBool      flg,f1,f2,f3;
350 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES)
351   char           *newpath;
352 #endif
353 
354   PetscFunctionBegin;
355   if (!name) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Trying to find routine with null name");
356 
357   *r = 0;
358   ierr = PetscFListGetPathAndFunction(name,&path,&function);CHKERRQ(ierr);
359 
360   /*
361         If path then append it to search libraries
362   */
363 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES)
364   if (path) {
365     ierr = PetscDLLibraryAppend(comm,&PetscDLLibrariesLoaded,path);CHKERRQ(ierr);
366   }
367 #endif
368 
369   while (entry) {
370     flg = PETSC_FALSE;
371     if (path && entry->path) {
372       ierr = PetscStrcmp(path,entry->path,&f1);CHKERRQ(ierr);
373       ierr = PetscStrcmp(function,entry->rname,&f2);CHKERRQ(ierr);
374       ierr = PetscStrcmp(function,entry->name,&f3);CHKERRQ(ierr);
375       flg =  (PetscBool) ((f1 && f2) || (f1 && f3));
376     } else if (!path) {
377       ierr = PetscStrcmp(function,entry->name,&f1);CHKERRQ(ierr);
378       ierr = PetscStrcmp(function,entry->rname,&f2);CHKERRQ(ierr);
379       flg =  (PetscBool) (f1 || f2);
380     } else {
381       ierr = PetscStrcmp(function,entry->name,&flg);CHKERRQ(ierr);
382       if (flg) {
383         ierr = PetscFree(function);CHKERRQ(ierr);
384         ierr = PetscStrallocpy(entry->rname,&function);CHKERRQ(ierr);
385       } else {
386         ierr = PetscStrcmp(function,entry->rname,&flg);CHKERRQ(ierr);
387       }
388     }
389 
390     if (flg) {
391       if (entry->routine) {
392         *r   = entry->routine;
393         ierr = PetscFree(path);CHKERRQ(ierr);
394         ierr = PetscFree(function);CHKERRQ(ierr);
395         PetscFunctionReturn(0);
396       }
397       if (!(entry->rname && entry->rname[0])) { /* The entry has been cleared */
398         ierr = PetscFree(function);CHKERRQ(ierr);
399         PetscFunctionReturn(0);
400       }
401       if ((path && entry->path && f3) || (!path && f1)) { /* convert name of function (alias) to actual function name */
402         ierr = PetscFree(function);CHKERRQ(ierr);
403         ierr = PetscStrallocpy(entry->rname,&function);CHKERRQ(ierr);
404       }
405 
406       /* it is not yet in memory so load from dynamic library */
407 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES)
408       newpath = path;
409       if (!path) newpath = entry->path;
410       ierr = PetscDLLibrarySym(comm,&PetscDLLibrariesLoaded,newpath,entry->rname,(void **)r);CHKERRQ(ierr);
411       if (*r) {
412         entry->routine = *r;
413         ierr = PetscFree(path);CHKERRQ(ierr);
414         ierr = PetscFree(function);CHKERRQ(ierr);
415         PetscFunctionReturn(0);
416       }
417 #endif
418     }
419     entry = entry->next;
420   }
421 
422 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES)
423   if (searchlibraries) {
424     /* Function never registered; try for it anyway */
425     ierr = PetscDLLibrarySym(comm,&PetscDLLibrariesLoaded,path,function,(void **)r);CHKERRQ(ierr);
426     ierr = PetscFree(path);CHKERRQ(ierr);
427     if (*r) {
428       ierr = PetscFListAdd(comm,&fl,name,name,*r);CHKERRQ(ierr);
429     }
430   }
431 #endif
432   ierr = PetscFree(function);CHKERRQ(ierr);
433   PetscFunctionReturn(0);
434 }
435 
436 #undef __FUNCT__
437 #define __FUNCT__ "PetscFListView"
438 /*@
439    PetscFListView - prints out contents of an PetscFList
440 
441    Collective over MPI_Comm
442 
443    Input Parameters:
444 +  list - the list of functions
445 -  viewer - currently ignored
446 
447    Level: developer
448 
449 .seealso: PetscFListAddDynamic(), PetscFListPrintTypes(), PetscFList
450 @*/
451 PetscErrorCode  PetscFListView(PetscFList list,PetscViewer viewer)
452 {
453   PetscErrorCode ierr;
454   PetscBool      iascii;
455 
456   PetscFunctionBegin;
457   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;
458   PetscValidPointer(list,1);
459   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
460 
461   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
462   if (!iascii) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Only ASCII viewer supported");
463 
464   while (list) {
465     if (list->path) {
466       ierr = PetscViewerASCIIPrintf(viewer," %s %s %s\n",list->path,list->name,list->rname);CHKERRQ(ierr);
467     } else {
468       ierr = PetscViewerASCIIPrintf(viewer," %s %s\n",list->name,list->rname);CHKERRQ(ierr);
469     }
470     list = list->next;
471   }
472   ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
473   PetscFunctionReturn(0);
474 }
475 
476 #undef __FUNCT__
477 #define __FUNCT__ "PetscFListGet"
478 /*@C
479    PetscFListGet - Gets an array the contains the entries in PetscFList, this is used
480          by help etc.
481 
482    Collective over MPI_Comm
483 
484    Input Parameter:
485 .  list   - list of types
486 
487    Output Parameter:
488 +  array - array of names
489 -  n - length of array
490 
491    Notes:
492        This allocates the array so that must be freed. BUT the individual entries are
493     not copied so should not be freed.
494 
495    Level: developer
496 
497 .seealso: PetscFListAddDynamic(), PetscFList
498 @*/
499 PetscErrorCode  PetscFListGet(PetscFList list,const char ***array,int *n)
500 {
501   PetscErrorCode ierr;
502   PetscInt       count = 0;
503   PetscFList     klist = list;
504 
505   PetscFunctionBegin;
506   while (list) {
507     list = list->next;
508     count++;
509   }
510   ierr  = PetscMalloc((count+1)*sizeof(char *),array);CHKERRQ(ierr);
511   count = 0;
512   while (klist) {
513     (*array)[count] = klist->name;
514     klist = klist->next;
515     count++;
516   }
517   (*array)[count] = 0;
518   *n = count+1;
519   PetscFunctionReturn(0);
520 }
521 
522 
523 #undef __FUNCT__
524 #define __FUNCT__ "PetscFListPrintTypes"
525 /*@C
526    PetscFListPrintTypes - Prints the methods available.
527 
528    Collective over MPI_Comm
529 
530    Input Parameters:
531 +  comm   - the communicator (usually MPI_COMM_WORLD)
532 .  fd     - file to print to, usually stdout
533 .  prefix - prefix to prepend to name (optional)
534 .  name   - option string (for example, "-ksp_type")
535 .  text - short description of the object (for example, "Krylov solvers")
536 .  man - name of manual page that discusses the object (for example, "KSPCreate")
537 .  list   - list of types
538 -  def - default (current) value
539 
540    Level: developer
541 
542 .seealso: PetscFListAddDynamic(), PetscFList
543 @*/
544 PetscErrorCode  PetscFListPrintTypes(MPI_Comm comm,FILE *fd,const char prefix[],const char name[],const char text[],const char man[],PetscFList list,const char def[])
545 {
546   PetscErrorCode ierr;
547   PetscInt       count = 0;
548   char           p[64];
549 
550   PetscFunctionBegin;
551   if (!fd) fd = PETSC_STDOUT;
552 
553   ierr = PetscStrcpy(p,"-");CHKERRQ(ierr);
554   if (prefix) {ierr = PetscStrcat(p,prefix);CHKERRQ(ierr);}
555   ierr = PetscFPrintf(comm,fd,"  %s%s <%s>: %s (one of)",p,name+1,def,text);CHKERRQ(ierr);
556 
557   while (list) {
558     ierr = PetscFPrintf(comm,fd," %s",list->name);CHKERRQ(ierr);
559     list = list->next;
560     count++;
561     if (count == 8) {ierr = PetscFPrintf(comm,fd,"\n     ");CHKERRQ(ierr);}
562   }
563   ierr = PetscFPrintf(comm,fd," (%s)\n",man);CHKERRQ(ierr);
564   PetscFunctionReturn(0);
565 }
566 
567 #undef __FUNCT__
568 #define __FUNCT__ "PetscFListDuplicate"
569 /*@
570     PetscFListDuplicate - Creates a new list from a given object list.
571 
572     Input Parameters:
573 .   fl   - pointer to list
574 
575     Output Parameters:
576 .   nl - the new list (should point to 0 to start, otherwise appends)
577 
578     Level: developer
579 
580 .seealso: PetscFList, PetscFListAdd(), PetscFlistDestroy()
581 
582 @*/
583 PetscErrorCode  PetscFListDuplicate(PetscFList fl,PetscFList *nl)
584 {
585   PetscErrorCode ierr;
586   char           path[PETSC_MAX_PATH_LEN];
587 
588   PetscFunctionBegin;
589   while (fl) {
590     /* this is silly, rebuild the complete pathname */
591     if (fl->path) {
592       ierr = PetscStrcpy(path,fl->path);CHKERRQ(ierr);
593       ierr = PetscStrcat(path,":");CHKERRQ(ierr);
594       ierr = PetscStrcat(path,fl->name);CHKERRQ(ierr);
595     } else {
596       ierr = PetscStrcpy(path,fl->name);CHKERRQ(ierr);
597     }
598     ierr = PetscFListAdd(PETSC_COMM_WORLD,nl,path,fl->rname,fl->routine);CHKERRQ(ierr);
599     fl   = fl->next;
600   }
601   PetscFunctionReturn(0);
602 }
603 
604 
605 #undef __FUNCT__
606 #define __FUNCT__ "PetscFListConcat"
607 /*
608     PetscFListConcat - joins name of a libary, and the path where it is located
609     into a single string.
610 
611     Input Parameters:
612 .   path   - path to the library name.
613 .   name   - name of the library
614 
615     Output Parameters:
616 .   fullname - the name that is the union of the path and the library name,
617                delimited by a semicolon, i.e., path:name
618 
619     Notes:
620     If the path is NULL, assumes that the name, specified also includes
621     the path as path:name
622 
623 */
624 PetscErrorCode  PetscFListConcat(const char path[],const char name[],char fullname[])
625 {
626   PetscErrorCode ierr;
627   PetscFunctionBegin;
628   if (path) {
629     ierr = PetscStrcpy(fullname,path);CHKERRQ(ierr);
630     ierr = PetscStrcat(fullname,":");CHKERRQ(ierr);
631     ierr = PetscStrcat(fullname,name);CHKERRQ(ierr);
632   } else {
633     ierr = PetscStrcpy(fullname,name);CHKERRQ(ierr);
634   }
635   PetscFunctionReturn(0);
636 }
637 
638 
639 
640 /* ------------------------------------------------------------------------------*/
641 struct _n_PetscOpFList {
642   char                 *op;                /* op name */
643   PetscInt             numArgs;            /* number of arguments to the operation */
644   char                 **argTypes;         /* list of argument types */
645   PetscVoidFunction    routine;            /* the routine */
646   char                 *url;               /* url naming the link library and the routine */
647   char                 *path;              /* path of link library containing routine */
648   char                 *name;              /* routine name in dynamic library */
649   PetscOpFList         next;              /* next pointer */
650   PetscOpFList         next_list;         /* used to maintain list of all lists for freeing */
651 };
652 
653 /*
654      Keep a linked list of PetscOfFLists so that we can destroy all the left-over ones.
655 */
656 static PetscOpFList   opallhead = 0;
657 
658 #undef __FUNCT__
659 #define __FUNCT__ "PetscOpFListAdd"
660 /*@C
661    PetscOpFListAdd - Given a routine, a string id, and the type names of arguments saves that routine in the  specified registry.
662 
663    Formally collective on comm.
664 
665    Input Parameters:
666 +  comm     - processors adding the op
667 .  fl       - list of known ops
668 .  url      - routine locator  (optional, if not using dynamic libraries and a nonempty fnc)
669 .  fnc      - function pointer (optional, if using dynamic libraries and a nonempty url)
670 .  op       - operation name
671 .  numArgs  - number of op arguments
672 -  argTypes - list of argument type names (const char*)
673 
674    Notes:
675    To remove a registered routine, pass in a PETSC_NULL url and fnc().
676 
677    url can be of the form  [/path/libname[.so.1.0]:]functionname[()]  where items in [] denote optional
678 
679    ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, or ${any environment variable}
680    occuring in url will be replaced with appropriate values.
681 
682    Level: developer
683 
684 .seealso: PetscOpFListDestroy(), PetscOpFList,  PetscFListAdd(), PetscFList
685 @*/
686 PetscErrorCode  PetscOpFListAdd(MPI_Comm comm, PetscOpFList *fl,const char url[],PetscVoidFunction fnc,const char op[], PetscInt numArgs, char* argTypes[])
687 {
688   PetscOpFList   entry,e,ne;
689   PetscErrorCode ierr;
690   char           *fpath,*fname;
691   PetscInt       i;
692 
693   PetscFunctionBegin;
694   if (!*fl) {
695     ierr           = PetscNew(struct _n_PetscOpFList,&entry);CHKERRQ(ierr);
696     ierr           = PetscStrallocpy(op,&entry->op);CHKERRQ(ierr);
697     ierr           = PetscStrallocpy(url,&(entry->url));CHKERRQ(ierr);
698     ierr           = PetscFListGetPathAndFunction(url,&fpath,&fname);CHKERRQ(ierr);
699     entry->path    = fpath;
700     entry->name    = fname;
701     entry->routine = fnc;
702     entry->numArgs = numArgs;
703     if (numArgs) {
704       ierr = PetscMalloc(sizeof(char*)*numArgs, &(entry->argTypes));CHKERRQ(ierr);
705       for (i = 0; i < numArgs; ++i) {
706         ierr = PetscStrallocpy(argTypes[i], &(entry->argTypes[i]));CHKERRQ(ierr);
707       }
708     }
709     entry->next    = 0;
710     *fl = entry;
711 
712     /* add this new list to list of all lists */
713     if (!opallhead) {
714       opallhead       = *fl;
715       (*fl)->next_list = 0;
716     } else {
717       ne               = opallhead;
718       opallhead        = *fl;
719       (*fl)->next_list = ne;
720     }
721   } else {
722     /* search list to see if it is already there */
723     e  = PETSC_NULL;
724     ne = *fl;
725     while (ne) {
726       PetscBool  match;
727       ierr = PetscStrcmp(ne->op,op,&match);CHKERRQ(ierr);
728       if (!match) goto next;
729       if (numArgs == ne->numArgs) match = PETSC_TRUE;
730       else match = PETSC_FALSE;
731       if (!match) goto next;
732       if (numArgs) {
733         for (i = 0; i < numArgs; ++i) {
734           ierr = PetscStrcmp(argTypes[i], ne->argTypes[i], &match);CHKERRQ(ierr);
735           if (!match) goto next;
736         }
737       }
738       if (!url && !fnc) {
739         /* remove this record */
740         if (e) e->next = ne->next;
741         ierr = PetscFree(ne->op);CHKERRQ(ierr);
742         ierr = PetscFree(ne->url);CHKERRQ(ierr);
743         ierr = PetscFree(ne->path);CHKERRQ(ierr);
744         ierr = PetscFree(ne->name);CHKERRQ(ierr);
745         if (numArgs) {
746           for (i = 0; i < numArgs; ++i) {
747             ierr = PetscFree(ne->argTypes[i]);CHKERRQ(ierr);
748           }
749           ierr = PetscFree(ne->argTypes);CHKERRQ(ierr);
750         }
751         ierr = PetscFree(ne);CHKERRQ(ierr);
752       } else {
753         /* Replace url, fpath, fname and fnc. */
754         ierr = PetscStrallocpy(url, &(ne->url));CHKERRQ(ierr);
755         ierr = PetscFListGetPathAndFunction(url,&fpath,&fname);CHKERRQ(ierr);
756         ierr = PetscFree(ne->path);CHKERRQ(ierr);
757         ierr = PetscFree(ne->name);CHKERRQ(ierr);
758         ne->path    = fpath;
759         ne->name    = fname;
760         ne->routine = fnc;
761       }
762       PetscFunctionReturn(0);
763       next: {e = ne; ne = ne->next;}
764     }
765     /* create new entry and add to end of list */
766     ierr           = PetscNew(struct _n_PetscOpFList,&entry);CHKERRQ(ierr);
767     ierr           = PetscStrallocpy(op,&entry->op);CHKERRQ(ierr);
768     entry->numArgs = numArgs;
769     if (numArgs) {
770       ierr = PetscMalloc(sizeof(char*)*numArgs, &(entry->argTypes));CHKERRQ(ierr);
771       for (i = 0; i < numArgs; ++i) {
772         ierr = PetscStrallocpy(argTypes[i], &(entry->argTypes[i]));CHKERRQ(ierr);
773       }
774     }
775     ierr = PetscStrallocpy(url, &(entry->url));CHKERRQ(ierr);
776     ierr           = PetscFListGetPathAndFunction(url,&fpath,&fname);CHKERRQ(ierr);
777     entry->path    = fpath;
778     entry->name    = fname;
779     entry->routine = fnc;
780     entry->next    = 0;
781     ne->next       = entry;
782   }
783   PetscFunctionReturn(0);
784 }
785 
786 #undef __FUNCT__
787 #define __FUNCT__ "PetscOpFListDestroy"
788 /*@C
789     PetscOpFListDestroy - Destroys a list of registered op routines.
790 
791     Input Parameter:
792 .   fl  - pointer to list
793 
794     Level: developer
795 
796 .seealso: PetscOpFListAdd(), PetscOpFList
797 @*/
798 PetscErrorCode  PetscOpFListDestroy(PetscOpFList *fl)
799 {
800   PetscOpFList     next,entry,tmp;
801   PetscErrorCode   ierr;
802   PetscInt         i;
803 
804   PetscFunctionBegin;
805   if (!*fl) PetscFunctionReturn(0);
806   if (!opallhead) PetscFunctionReturn(0);
807 
808   /*
809        Remove this entry from the master Op list (if it is in it)
810   */
811   if (opallhead == *fl) {
812     if (opallhead->next_list) {
813       opallhead = opallhead->next_list;
814     } else {
815       opallhead = 0;
816     }
817   } else {
818     tmp = opallhead;
819     while (tmp->next_list != *fl) {
820       tmp = tmp->next_list;
821       if (!tmp->next_list) break;
822     }
823     if (tmp->next_list) tmp->next_list = tmp->next_list->next_list;
824   }
825 
826   /* free this list */
827   entry = *fl;
828   while (entry) {
829     next = entry->next;
830     ierr = PetscFree(entry->op);CHKERRQ(ierr);
831     for (i = 0; i < entry->numArgs; ++i) {
832       ierr = PetscFree(entry->argTypes[i]);CHKERRQ(ierr);
833     }
834     ierr = PetscFree(entry->argTypes);CHKERRQ(ierr);
835     ierr = PetscFree(entry->url);CHKERRQ(ierr);
836     ierr = PetscFree(entry->path);CHKERRQ(ierr);
837     ierr = PetscFree(entry->name);CHKERRQ(ierr);
838     ierr = PetscFree(entry);CHKERRQ(ierr);
839     entry = next;
840   }
841   *fl = 0;
842   PetscFunctionReturn(0);
843 }
844 
845 /*
846    Destroys all the function lists that anyone has every registered, such as MatOpList, etc.
847 */
848 #undef __FUNCT__
849 #define __FUNCT__ "PetscOpFListDestroyAll"
850 PetscErrorCode  PetscOpFListDestroyAll(void)
851 {
852   PetscOpFList     tmp2,tmp1 = opallhead;
853   PetscErrorCode ierr;
854 
855   PetscFunctionBegin;
856   while (tmp1) {
857     tmp2 = tmp1->next_list;
858     ierr = PetscOpFListDestroy(&tmp1);CHKERRQ(ierr);
859     tmp1 = tmp2;
860   }
861   opallhead = 0;
862   PetscFunctionReturn(0);
863 }
864 
865 #undef __FUNCT__
866 #define __FUNCT__ "PetscOpFListFind"
867 /*@C
868     PetscOpFListFind - Given a name, finds the matching op routine based on the declared arguments' type names.
869 
870     Formally collective on MPI_Comm
871 
872     Input Parameters:
873 +   comm     - processes looking for the op
874 .   fl       - pointer to list of known ops
875 .   op       - operation name
876 .   numArgs  - number of op arguments
877 -   argTypes - list of argument type names
878 
879     Output Parameters:
880 .   r       - routine implementing op with the given arg types
881 
882     Level: developer
883 
884     Notes: This is used to implement double dispatch and multiple dispatch based on the type names of the function arguments
885 
886 .seealso: PetscOpFListAdd(), PetscOpFList
887 @*/
888 PetscErrorCode  PetscOpFListFind(MPI_Comm comm, PetscOpFList fl,PetscVoidFunction *r, const char* op, PetscInt numArgs, char* argTypes[])
889 {
890   PetscOpFList   entry;
891   PetscErrorCode ierr;
892   PetscBool      match;
893   PetscInt       i;
894 
895   PetscFunctionBegin;
896   PetscValidPointer(r,3);
897   if (!op) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Attempting to find operation with null name");
898   *r = PETSC_NULL;
899   match = PETSC_FALSE;
900   entry = fl;
901   while (entry) {
902     ierr = PetscStrcmp(entry->op,op,&match);CHKERRQ(ierr);
903     if (!match) goto next;
904     if (numArgs == entry->numArgs)
905       match = PETSC_TRUE;
906     else
907       match = PETSC_FALSE;
908     if (!match) goto next;
909     if (numArgs) {
910       for (i = 0; i < numArgs; ++i) {
911         ierr = PetscStrcmp(argTypes[i], entry->argTypes[i], &match);CHKERRQ(ierr);
912         if (!match) goto next;
913       }
914     }
915     break;
916     next: entry = entry->next;
917   }
918   if (match) {
919     if (entry->routine) {
920       *r   = entry->routine;
921     }
922 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES)
923     else {
924       /* it is not yet in memory so load from dynamic library */
925       ierr = PetscDLLibrarySym(comm,&PetscDLLibrariesLoaded,entry->path,entry->name,(void **)r);CHKERRQ(ierr);
926       if (*r) {
927         entry->routine = *r;
928       }
929     }
930 #endif
931   }
932 
933   PetscFunctionReturn(0);
934 }
935 
936 #undef __FUNCT__
937 #define __FUNCT__ "PetscOpFListView"
938 /*@C
939    PetscOpFListView - prints out contents of a PetscOpFList
940 
941    Collective on viewer
942 
943    Input Parameters:
944 +  list   - the list of functions
945 -  viewer - ASCII viewer   Level: developer
946 
947 .seealso: PetscOpFListAdd(), PetscOpFList
948 @*/
949 PetscErrorCode  PetscOpFListView(PetscOpFList list,PetscViewer viewer)
950 {
951   PetscErrorCode ierr;
952   PetscBool      iascii;
953   PetscInt       i;
954 
955   PetscFunctionBegin;
956   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;
957   PetscValidPointer(list,1);
958   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
959 
960   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
961   if (!iascii) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Only ASCII viewer supported");
962 
963   while (list) {
964     if (list->url) {
965       ierr = PetscViewerASCIIPrintf(viewer," %s: ",list->url);CHKERRQ(ierr);
966     }
967     ierr = PetscViewerASCIIPrintf(viewer, "%s(", list->op);CHKERRQ(ierr);
968     for (i = 0; i < list->numArgs;++i) {
969       if (i > 0) {
970         ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);
971       }
972       ierr = PetscViewerASCIIPrintf(viewer, "%s", list->argTypes[i]);CHKERRQ(ierr);
973     }
974     ierr = PetscViewerASCIIPrintf(viewer, ")\n");CHKERRQ(ierr);
975     list = list->next;
976   }
977   PetscFunctionReturn(0);
978 }
979