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