xref: /petsc/src/sys/dll/reg.c (revision 8cc058d9cd56c1ccb3be12a47760ddfc446aaffc)
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("ksp",&found);CHKERRQ(ierr);
112   if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate PETSc KSP dynamic library \n You cannot move the dynamic libraries!");
113   ierr = PetscLoadDynamicLibrary("snes",&found);CHKERRQ(ierr);
114   if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate PETSc SNES dynamic library \n You cannot move the dynamic libraries!");
115   ierr = PetscLoadDynamicLibrary("ts",&found);CHKERRQ(ierr);
116   if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate PETSc TS dynamic library \n You cannot move the dynamic libraries!");
117 #endif
118 #endif
119 
120   nmax = 32;
121   ierr = PetscOptionsGetStringArray(NULL,"-dll_append",libname,&nmax,NULL);CHKERRQ(ierr);
122   for (i=0; i<nmax; i++) {
123     ierr = PetscDLLibraryAppend(PETSC_COMM_WORLD,&PetscDLLibrariesLoaded,libname[i]);CHKERRQ(ierr);
124     ierr = PetscFree(libname[i]);CHKERRQ(ierr);
125   }
126   PetscFunctionReturn(0);
127 }
128 
129 #undef __FUNCT__
130 #define __FUNCT__ "PetscFinalize_DynamicLibraries"
131 /*
132      PetscFinalize_DynamicLibraries - Closes the opened dynamic libraries.
133 */
134 PetscErrorCode PetscFinalize_DynamicLibraries(void)
135 {
136   PetscErrorCode ierr;
137   PetscBool      flg = PETSC_FALSE;
138 
139   PetscFunctionBegin;
140   ierr = PetscOptionsGetBool(NULL,"-dll_view",&flg,NULL);CHKERRQ(ierr);
141   if (flg) { ierr = PetscDLLibraryPrintPath(PetscDLLibrariesLoaded);CHKERRQ(ierr); }
142   ierr = PetscDLLibraryClose(PetscDLLibrariesLoaded);CHKERRQ(ierr);
143 
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 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 
234         ne->path    = fpath;
235         ne->rname   = fname;
236         ne->routine = fnc;
237         PetscFunctionReturn(0);
238       }
239       if (ne->next) ne = ne->next;
240       else break;
241     }
242     /* create new entry and add to end of list */
243     ierr           = PetscNew(struct _n_PetscFunctionList,&entry);CHKERRQ(ierr);
244     ierr           = PetscStrallocpy(name,&entry->name);CHKERRQ(ierr);
245     ierr           = PetscFunctionListGetPathAndFunction(rname,&fpath,&fname);CHKERRQ(ierr);
246     entry->path    = fpath;
247     entry->rname   = fname;
248     entry->routine = fnc;
249     entry->next    = 0;
250     ne->next       = entry;
251   }
252   PetscFunctionReturn(0);
253 }
254 
255 #undef __FUNCT__
256 #define __FUNCT__ "PetscFunctionListDestroy"
257 /*@
258     PetscFunctionListDestroy - Destroys a list of registered routines.
259 
260     Input Parameter:
261 .   fl  - pointer to list
262 
263     Level: developer
264 
265 .seealso: PetscFunctionListAddDynamic(), PetscFunctionList
266 @*/
267 PetscErrorCode  PetscFunctionListDestroy(PetscFunctionList *fl)
268 {
269   PetscFunctionList next,entry,tmp = dlallhead;
270   PetscErrorCode    ierr;
271 
272   PetscFunctionBegin;
273   if (!*fl) PetscFunctionReturn(0);
274   if (!dlallhead) PetscFunctionReturn(0);
275 
276   /*
277        Remove this entry from the master DL list (if it is in it)
278   */
279   if (dlallhead == *fl) {
280     if (dlallhead->next_list) dlallhead = dlallhead->next_list;
281     else dlallhead = 0;
282   } else {
283     while (tmp->next_list != *fl) {
284       tmp = tmp->next_list;
285       if (!tmp->next_list) break;
286     }
287     if (tmp->next_list) tmp->next_list = tmp->next_list->next_list;
288   }
289 
290   /* free this list */
291   entry = *fl;
292   while (entry) {
293     next  = entry->next;
294     ierr  = PetscFree(entry->path);CHKERRQ(ierr);
295     ierr  = PetscFree(entry->name);CHKERRQ(ierr);
296     ierr  = PetscFree(entry->rname);CHKERRQ(ierr);
297     ierr  = PetscFree(entry);CHKERRQ(ierr);
298     entry = next;
299   }
300   *fl = 0;
301   PetscFunctionReturn(0);
302 }
303 
304 /*
305    Destroys all the function lists that anyone has every registered, such as KSPList, VecList, etc.
306 */
307 #undef __FUNCT__
308 #define __FUNCT__ "PetscFunctionListDestroyAll"
309 PetscErrorCode  PetscFunctionListDestroyAll(void)
310 {
311   PetscFunctionList tmp2,tmp1 = dlallhead;
312   PetscErrorCode    ierr;
313 
314   PetscFunctionBegin;
315   while (tmp1) {
316     tmp2 = tmp1->next_list;
317     ierr = PetscFunctionListDestroy(&tmp1);CHKERRQ(ierr);
318     tmp1 = tmp2;
319   }
320   dlallhead = 0;
321   PetscFunctionReturn(0);
322 }
323 
324 #undef __FUNCT__
325 #define __FUNCT__ "PetscFunctionListFind"
326 /*@C
327     PetscFunctionListFind - Given a name, finds the matching routine.
328 
329     Input Parameters:
330 +   fl   - pointer to list
331 .   comm - processors looking for routine
332 .   name - name string
333 -   searchlibraries - if not found in the list then search the dynamic libraries and executable for the symbol
334 
335     Output Parameters:
336 .   r - the routine
337 
338     Level: developer
339 
340 .seealso: PetscFunctionListAddDynamic(), PetscFunctionList
341 @*/
342 PetscErrorCode  PetscFunctionListFind(MPI_Comm comm,PetscFunctionList fl,const char name[],PetscBool searchlibraries,void (**r)(void))
343 {
344   PetscFunctionList entry = fl;
345   PetscErrorCode    ierr;
346   char              *function,*path;
347   PetscBool         flg,f1,f2,f3;
348 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES)
349   char              *newpath;
350 #endif
351 
352   PetscFunctionBegin;
353   if (!name) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Trying to find routine with null name");
354 
355   *r = 0;
356   ierr = PetscFunctionListGetPathAndFunction(name,&path,&function);CHKERRQ(ierr);
357 
358   /*
359         If path then append it to search libraries
360   */
361 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES)
362   if (path) {
363     ierr = PetscDLLibraryAppend(comm,&PetscDLLibrariesLoaded,path);CHKERRQ(ierr);
364   }
365 #endif
366 
367   while (entry) {
368     flg = PETSC_FALSE;
369     if (path && entry->path) {
370       ierr = PetscStrcmp(path,entry->path,&f1);CHKERRQ(ierr);
371       ierr = PetscStrcmp(function,entry->rname,&f2);CHKERRQ(ierr);
372       ierr = PetscStrcmp(function,entry->name,&f3);CHKERRQ(ierr);
373       flg  =  (PetscBool) ((f1 && f2) || (f1 && f3));
374     } else if (!path) {
375       ierr = PetscStrcmp(function,entry->name,&f1);CHKERRQ(ierr);
376       ierr = PetscStrcmp(function,entry->rname,&f2);CHKERRQ(ierr);
377       flg  =  (PetscBool) (f1 || f2);
378     } else {
379       ierr = PetscStrcmp(function,entry->name,&flg);CHKERRQ(ierr);
380       if (flg) {
381         ierr = PetscFree(function);CHKERRQ(ierr);
382         ierr = PetscStrallocpy(entry->rname,&function);CHKERRQ(ierr);
383       } else {
384         ierr = PetscStrcmp(function,entry->rname,&flg);CHKERRQ(ierr);
385       }
386     }
387 
388     if (flg) {
389       if (entry->routine) {
390         *r   = entry->routine;
391         ierr = PetscFree(path);CHKERRQ(ierr);
392         ierr = PetscFree(function);CHKERRQ(ierr);
393         PetscFunctionReturn(0);
394       }
395       if (!(entry->rname && entry->rname[0])) { /* The entry has been cleared */
396         ierr = PetscFree(function);CHKERRQ(ierr);
397         PetscFunctionReturn(0);
398       }
399       if ((path && entry->path && f3) || (!path && f1)) { /* convert name of function (alias) to actual function name */
400         ierr = PetscFree(function);CHKERRQ(ierr);
401         ierr = PetscStrallocpy(entry->rname,&function);CHKERRQ(ierr);
402       }
403 
404       /* it is not yet in memory so load from dynamic library */
405 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES)
406       newpath = path;
407       if (!path) newpath = entry->path;
408       ierr = PetscDLLibrarySym(comm,&PetscDLLibrariesLoaded,newpath,entry->rname,(void**)r);CHKERRQ(ierr);
409       if (*r) {
410         entry->routine = *r;
411 
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