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