xref: /petsc/src/sys/dll/reg.c (revision b6bfaf9a0a178e626c17e7b8aafd5e3bedcd9a6d)
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__ "PetscFunctionListGetPathAndFunction"
10 PetscErrorCode  PetscFunctionListGetPathAndFunction(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   PetscFunctionReturn(0);
128 }
129 
130 #undef __FUNCT__
131 #define __FUNCT__ "PetscFinalize_DynamicLibraries"
132 /*
133      PetscFinalize_DynamicLibraries - Closes the opened dynamic libraries.
134 */
135 PetscErrorCode PetscFinalize_DynamicLibraries(void)
136 {
137   PetscErrorCode ierr;
138   PetscBool      flg = PETSC_FALSE;
139 
140   PetscFunctionBegin;
141   ierr = PetscOptionsGetBool(PETSC_NULL,"-dll_view",&flg,PETSC_NULL);CHKERRQ(ierr);
142   if (flg) { ierr = PetscDLLibraryPrintPath(PetscDLLibrariesLoaded);CHKERRQ(ierr); }
143   ierr = PetscDLLibraryClose(PetscDLLibrariesLoaded);CHKERRQ(ierr);
144   PetscDLLibrariesLoaded = 0;
145   PetscFunctionReturn(0);
146 }
147 
148 
149 
150 /* ------------------------------------------------------------------------------*/
151 struct _n_PetscFunctionList {
152   void               (*routine)(void);   /* the routine */
153   char               *path;              /* path of link library containing routine */
154   char               *name;              /* string to identify routine */
155   char               *rname;             /* routine name in dynamic library */
156   PetscFunctionList  next;               /* next pointer */
157   PetscFunctionList  next_list;          /* used to maintain list of all lists for freeing */
158 };
159 
160 /*
161      Keep a linked list of PetscFunctionLists so that we can destroy all the left-over ones.
162 */
163 static PetscFunctionList   dlallhead = 0;
164 
165 #undef __FUNCT__
166 #define __FUNCT__ "PetscFunctionListAdd"
167 /*@C
168    PetscFunctionListAdd - Given a routine and a string id, saves that routine in the
169    specified registry.
170 
171      Formally Collective on MPI_Comm
172 
173    Input Parameters:
174 +  comm  - the comm where this exists (currently not used)
175 .  fl    - pointer registry
176 .  name  - string to identify routine
177 .  rname - routine name in dynamic library
178 -  fnc   - function pointer (optional if using dynamic libraries)
179 
180    Notes:
181    To remove a registered routine, pass in a PETSC_NULL rname and fnc().
182 
183    Users who wish to register new classes for use by a particular PETSc
184    component (e.g., SNES) should generally call the registration routine
185    for that particular component (e.g., SNESRegisterDynamic()) instead of
186    calling PetscFunctionListAdd() directly.
187 
188    ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, or ${any environmental variable}
189   occuring in pathname will be replaced with appropriate values.
190 
191    Level: developer
192 
193 .seealso: PetscFunctionListDestroy(), SNESRegisterDynamic(), KSPRegisterDynamic(),
194           PCRegisterDynamic(), TSRegisterDynamic(), PetscFunctionList
195 @*/
196 PetscErrorCode  PetscFunctionListAdd(MPI_Comm comm,PetscFunctionList *fl,const char name[],const char rname[],void (*fnc)(void))
197 {
198   PetscFunctionList entry,ne;
199   PetscErrorCode    ierr;
200   char              *fpath,*fname;
201 
202   PetscFunctionBegin;
203   if (!*fl) {
204     ierr           = PetscNew(struct _n_PetscFunctionList,&entry);CHKERRQ(ierr);
205     ierr           = PetscStrallocpy(name,&entry->name);CHKERRQ(ierr);
206     ierr           = PetscFunctionListGetPathAndFunction(rname,&fpath,&fname);CHKERRQ(ierr);
207     entry->path    = fpath;
208     entry->rname   = fname;
209     entry->routine = fnc;
210     entry->next    = 0;
211     *fl = entry;
212 
213     /* add this new list to list of all lists */
214     if (!dlallhead) {
215       dlallhead        = *fl;
216       (*fl)->next_list = 0;
217     } else {
218       ne               = dlallhead;
219       dlallhead        = *fl;
220       (*fl)->next_list = ne;
221     }
222   } else {
223     /* search list to see if it is already there */
224     ne = *fl;
225     while (ne) {
226       PetscBool  founddup;
227 
228       ierr = PetscStrcmp(ne->name,name,&founddup);CHKERRQ(ierr);
229       if (founddup) { /* found duplicate */
230         ierr = PetscFunctionListGetPathAndFunction(rname,&fpath,&fname);CHKERRQ(ierr);
231         ierr = PetscFree(ne->path);CHKERRQ(ierr);
232         ierr = PetscFree(ne->rname);CHKERRQ(ierr);
233         ne->path    = fpath;
234         ne->rname   = fname;
235         ne->routine = fnc;
236         PetscFunctionReturn(0);
237       }
238       if (ne->next) ne = ne->next; else break;
239     }
240     /* create new entry and add to end of list */
241     ierr           = PetscNew(struct _n_PetscFunctionList,&entry);CHKERRQ(ierr);
242     ierr           = PetscStrallocpy(name,&entry->name);CHKERRQ(ierr);
243     ierr           = PetscFunctionListGetPathAndFunction(rname,&fpath,&fname);CHKERRQ(ierr);
244     entry->path    = fpath;
245     entry->rname   = fname;
246     entry->routine = fnc;
247     entry->next    = 0;
248     ne->next       = entry;
249   }
250   PetscFunctionReturn(0);
251 }
252 
253 #undef __FUNCT__
254 #define __FUNCT__ "PetscFunctionListDestroy"
255 /*@
256     PetscFunctionListDestroy - Destroys a list of registered routines.
257 
258     Input Parameter:
259 .   fl  - pointer to list
260 
261     Level: developer
262 
263 .seealso: PetscFunctionListAddDynamic(), PetscFunctionList
264 @*/
265 PetscErrorCode  PetscFunctionListDestroy(PetscFunctionList *fl)
266 {
267   PetscFunctionList next,entry,tmp = dlallhead;
268   PetscErrorCode    ierr;
269 
270   PetscFunctionBegin;
271   if (!*fl) PetscFunctionReturn(0);
272   if (!dlallhead) PetscFunctionReturn(0);
273 
274   /*
275        Remove this entry from the master DL list (if it is in it)
276   */
277   if (dlallhead == *fl) {
278     if (dlallhead->next_list) {
279       dlallhead = dlallhead->next_list;
280     } else {
281       dlallhead = 0;
282     }
283   } else {
284     while (tmp->next_list != *fl) {
285       tmp = tmp->next_list;
286       if (!tmp->next_list) break;
287     }
288     if (tmp->next_list) tmp->next_list = tmp->next_list->next_list;
289   }
290 
291   /* free this list */
292   entry = *fl;
293   while (entry) {
294     next = entry->next;
295     ierr = PetscFree(entry->path);CHKERRQ(ierr);
296     ierr = PetscFree(entry->name);CHKERRQ(ierr);
297     ierr = PetscFree(entry->rname);CHKERRQ(ierr);
298     ierr = PetscFree(entry);CHKERRQ(ierr);
299     entry = next;
300   }
301   *fl = 0;
302   PetscFunctionReturn(0);
303 }
304 
305 /*
306    Destroys all the function lists that anyone has every registered, such as KSPList, VecList, etc.
307 */
308 #undef __FUNCT__
309 #define __FUNCT__ "PetscFunctionListDestroyAll"
310 PetscErrorCode  PetscFunctionListDestroyAll(void)
311 {
312   PetscFunctionList tmp2,tmp1 = dlallhead;
313   PetscErrorCode    ierr;
314 
315   PetscFunctionBegin;
316   while (tmp1) {
317     tmp2 = tmp1->next_list;
318     ierr = PetscFunctionListDestroy(&tmp1);CHKERRQ(ierr);
319     tmp1 = tmp2;
320   }
321   dlallhead = 0;
322   PetscFunctionReturn(0);
323 }
324 
325 #undef __FUNCT__
326 #define __FUNCT__ "PetscFunctionListFind"
327 /*@C
328     PetscFunctionListFind - Given a name, finds the matching routine.
329 
330     Input Parameters:
331 +   fl   - pointer to list
332 .   comm - processors looking for routine
333 .   name - name string
334 -   searchlibraries - if not found in the list then search the dynamic libraries and executable for the symbol
335 
336     Output Parameters:
337 .   r - the routine
338 
339     Level: developer
340 
341 .seealso: PetscFunctionListAddDynamic(), PetscFunctionList
342 @*/
343 PetscErrorCode  PetscFunctionListFind(MPI_Comm comm,PetscFunctionList fl,const char name[],PetscBool searchlibraries,void (**r)(void))
344 {
345   PetscFunctionList entry = fl;
346   PetscErrorCode    ierr;
347   char              *function,*path;
348   PetscBool         flg,f1,f2,f3;
349 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES)
350   char              *newpath;
351 #endif
352 
353   PetscFunctionBegin;
354   if (!name) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Trying to find routine with null name");
355 
356   *r = 0;
357   ierr = PetscFunctionListGetPathAndFunction(name,&path,&function);CHKERRQ(ierr);
358 
359   /*
360         If path then append it to search libraries
361   */
362 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES)
363   if (path) {
364     ierr = PetscDLLibraryAppend(comm,&PetscDLLibrariesLoaded,path);CHKERRQ(ierr);
365   }
366 #endif
367 
368   while (entry) {
369     flg = PETSC_FALSE;
370     if (path && entry->path) {
371       ierr = PetscStrcmp(path,entry->path,&f1);CHKERRQ(ierr);
372       ierr = PetscStrcmp(function,entry->rname,&f2);CHKERRQ(ierr);
373       ierr = PetscStrcmp(function,entry->name,&f3);CHKERRQ(ierr);
374       flg =  (PetscBool) ((f1 && f2) || (f1 && f3));
375     } else if (!path) {
376       ierr = PetscStrcmp(function,entry->name,&f1);CHKERRQ(ierr);
377       ierr = PetscStrcmp(function,entry->rname,&f2);CHKERRQ(ierr);
378       flg =  (PetscBool) (f1 || f2);
379     } else {
380       ierr = PetscStrcmp(function,entry->name,&flg);CHKERRQ(ierr);
381       if (flg) {
382         ierr = PetscFree(function);CHKERRQ(ierr);
383         ierr = PetscStrallocpy(entry->rname,&function);CHKERRQ(ierr);
384       } else {
385         ierr = PetscStrcmp(function,entry->rname,&flg);CHKERRQ(ierr);
386       }
387     }
388 
389     if (flg) {
390       if (entry->routine) {
391         *r   = entry->routine;
392         ierr = PetscFree(path);CHKERRQ(ierr);
393         ierr = PetscFree(function);CHKERRQ(ierr);
394         PetscFunctionReturn(0);
395       }
396       if (!(entry->rname && entry->rname[0])) { /* The entry has been cleared */
397         ierr = PetscFree(function);CHKERRQ(ierr);
398         PetscFunctionReturn(0);
399       }
400       if ((path && entry->path && f3) || (!path && f1)) { /* convert name of function (alias) to actual function name */
401         ierr = PetscFree(function);CHKERRQ(ierr);
402         ierr = PetscStrallocpy(entry->rname,&function);CHKERRQ(ierr);
403       }
404 
405       /* it is not yet in memory so load from dynamic library */
406 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES)
407       newpath = path;
408       if (!path) newpath = entry->path;
409       ierr = PetscDLLibrarySym(comm,&PetscDLLibrariesLoaded,newpath,entry->rname,(void **)r);CHKERRQ(ierr);
410       if (*r) {
411         entry->routine = *r;
412         ierr = PetscFree(path);CHKERRQ(ierr);
413         ierr = PetscFree(function);CHKERRQ(ierr);
414         PetscFunctionReturn(0);
415       }
416 #endif
417     }
418     entry = entry->next;
419   }
420 
421 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES)
422   if (searchlibraries) {
423     /* Function never registered; try for it anyway */
424     ierr = PetscDLLibrarySym(comm,&PetscDLLibrariesLoaded,path,function,(void **)r);CHKERRQ(ierr);
425     ierr = PetscFree(path);CHKERRQ(ierr);
426     if (*r) {
427       ierr = PetscFunctionListAdd(comm,&fl,name,name,*r);CHKERRQ(ierr);
428     }
429   }
430 #endif
431   ierr = PetscFree(function);CHKERRQ(ierr);
432   PetscFunctionReturn(0);
433 }
434 
435 #undef __FUNCT__
436 #define __FUNCT__ "PetscFunctionListView"
437 /*@
438    PetscFunctionListView - prints out contents of an PetscFunctionList
439 
440    Collective over MPI_Comm
441 
442    Input Parameters:
443 +  list - the list of functions
444 -  viewer - currently ignored
445 
446    Level: developer
447 
448 .seealso: PetscFunctionListAddDynamic(), PetscFunctionListPrintTypes(), PetscFunctionList
449 @*/
450 PetscErrorCode  PetscFunctionListView(PetscFunctionList list,PetscViewer viewer)
451 {
452   PetscErrorCode ierr;
453   PetscBool      iascii;
454 
455   PetscFunctionBegin;
456   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;
457   PetscValidPointer(list,1);
458   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
459 
460   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
461   if (!iascii) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Only ASCII viewer supported");
462 
463   while (list) {
464     if (list->path) {
465       ierr = PetscViewerASCIIPrintf(viewer," %s %s %s\n",list->path,list->name,list->rname);CHKERRQ(ierr);
466     } else {
467       ierr = PetscViewerASCIIPrintf(viewer," %s %s\n",list->name,list->rname);CHKERRQ(ierr);
468     }
469     list = list->next;
470   }
471   ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
472   PetscFunctionReturn(0);
473 }
474 
475 #undef __FUNCT__
476 #define __FUNCT__ "PetscFunctionListGet"
477 /*@C
478    PetscFunctionListGet - Gets an array the contains the entries in PetscFunctionList, this is used
479          by help etc.
480 
481    Collective over MPI_Comm
482 
483    Input Parameter:
484 .  list   - list of types
485 
486    Output Parameter:
487 +  array - array of names
488 -  n - length of array
489 
490    Notes:
491        This allocates the array so that must be freed. BUT the individual entries are
492     not copied so should not be freed.
493 
494    Level: developer
495 
496 .seealso: PetscFunctionListAddDynamic(), PetscFunctionList
497 @*/
498 PetscErrorCode  PetscFunctionListGet(PetscFunctionList list,const char ***array,int *n)
499 {
500   PetscErrorCode    ierr;
501   PetscInt          count = 0;
502   PetscFunctionList klist = list;
503 
504   PetscFunctionBegin;
505   while (list) {
506     list = list->next;
507     count++;
508   }
509   ierr  = PetscMalloc((count+1)*sizeof(char *),array);CHKERRQ(ierr);
510   count = 0;
511   while (klist) {
512     (*array)[count] = klist->name;
513     klist = klist->next;
514     count++;
515   }
516   (*array)[count] = 0;
517   *n = count+1;
518   PetscFunctionReturn(0);
519 }
520 
521 
522 #undef __FUNCT__
523 #define __FUNCT__ "PetscFunctionListPrintTypes"
524 /*@C
525    PetscFunctionListPrintTypes - Prints the methods available.
526 
527    Collective over MPI_Comm
528 
529    Input Parameters:
530 +  comm   - the communicator (usually MPI_COMM_WORLD)
531 .  fd     - file to print to, usually stdout
532 .  prefix - prefix to prepend to name (optional)
533 .  name   - option string (for example, "-ksp_type")
534 .  text - short description of the object (for example, "Krylov solvers")
535 .  man - name of manual page that discusses the object (for example, "KSPCreate")
536 .  list   - list of types
537 -  def - default (current) value
538 
539    Level: developer
540 
541 .seealso: PetscFunctionListAddDynamic(), PetscFunctionList
542 @*/
543 PetscErrorCode  PetscFunctionListPrintTypes(MPI_Comm comm,FILE *fd,const char prefix[],const char name[],const char text[],const char man[],PetscFunctionList list,const char def[])
544 {
545   PetscErrorCode ierr;
546   PetscInt       count = 0;
547   char           p[64];
548 
549   PetscFunctionBegin;
550   if (!fd) fd = PETSC_STDOUT;
551 
552   ierr = PetscStrcpy(p,"-");CHKERRQ(ierr);
553   if (prefix) {ierr = PetscStrcat(p,prefix);CHKERRQ(ierr);}
554   ierr = PetscFPrintf(comm,fd,"  %s%s <%s>: %s (one of)",p,name+1,def,text);CHKERRQ(ierr);
555 
556   while (list) {
557     ierr = PetscFPrintf(comm,fd," %s",list->name);CHKERRQ(ierr);
558     list = list->next;
559     count++;
560     if (count == 8) {ierr = PetscFPrintf(comm,fd,"\n     ");CHKERRQ(ierr);}
561   }
562   ierr = PetscFPrintf(comm,fd," (%s)\n",man);CHKERRQ(ierr);
563   PetscFunctionReturn(0);
564 }
565 
566 #undef __FUNCT__
567 #define __FUNCT__ "PetscFunctionListDuplicate"
568 /*@
569     PetscFunctionListDuplicate - Creates a new list from a given object list.
570 
571     Input Parameters:
572 .   fl   - pointer to list
573 
574     Output Parameters:
575 .   nl - the new list (should point to 0 to start, otherwise appends)
576 
577     Level: developer
578 
579 .seealso: PetscFunctionList, PetscFunctionListAdd(), PetscFlistDestroy()
580 
581 @*/
582 PetscErrorCode  PetscFunctionListDuplicate(PetscFunctionList fl,PetscFunctionList *nl)
583 {
584   PetscErrorCode ierr;
585   char           path[PETSC_MAX_PATH_LEN];
586 
587   PetscFunctionBegin;
588   while (fl) {
589     /* this is silly, rebuild the complete pathname */
590     if (fl->path) {
591       ierr = PetscStrcpy(path,fl->path);CHKERRQ(ierr);
592       ierr = PetscStrcat(path,":");CHKERRQ(ierr);
593       ierr = PetscStrcat(path,fl->name);CHKERRQ(ierr);
594     } else {
595       ierr = PetscStrcpy(path,fl->name);CHKERRQ(ierr);
596     }
597     ierr = PetscFunctionListAdd(PETSC_COMM_WORLD,nl,path,fl->rname,fl->routine);CHKERRQ(ierr);
598     fl   = fl->next;
599   }
600   PetscFunctionReturn(0);
601 }
602 
603 
604 #undef __FUNCT__
605 #define __FUNCT__ "PetscFunctionListConcat"
606 /*
607     PetscFunctionListConcat - joins name of a libary, and the path where it is located
608     into a single string.
609 
610     Input Parameters:
611 .   path   - path to the library name.
612 .   name   - name of the library
613 
614     Output Parameters:
615 .   fullname - the name that is the union of the path and the library name,
616                delimited by a semicolon, i.e., path:name
617 
618     Notes:
619     If the path is NULL, assumes that the name, specified also includes
620     the path as path:name
621 
622 */
623 PetscErrorCode  PetscFunctionListConcat(const char path[],const char name[],char fullname[])
624 {
625   PetscErrorCode ierr;
626 
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