xref: /petsc/src/sys/dll/reg.c (revision cc55f3b16c70bf5e3ec0795ef60d9fd033167191)
1 
2 /*
3     Provides a general mechanism to allow one to register new routines in
4     dynamic libraries for many of the PETSc objects (including, e.g., KSP and PC).
5 */
6 #include <petscsys.h>           /*I "petscsys.h" I*/
7 
8 #undef __FUNCT__
9 #define __FUNCT__ "PetscFListGetPathAndFunction"
10 PetscErrorCode  PetscFListGetPathAndFunction(const char name[],char *path[],char *function[])
11 {
12   PetscErrorCode ierr;
13   char           work[PETSC_MAX_PATH_LEN],*lfunction;
14 
15   PetscFunctionBegin;
16   ierr = PetscStrncpy(work,name,sizeof work);CHKERRQ(ierr);
17   work[sizeof work - 1] = 0;
18   ierr = PetscStrchr(work,':',&lfunction);CHKERRQ(ierr);
19   if (lfunction != work && lfunction && lfunction[1] != ':') {
20     lfunction[0] = 0;
21     ierr = PetscStrallocpy(work,path);CHKERRQ(ierr);
22     ierr = PetscStrallocpy(lfunction+1,function);CHKERRQ(ierr);
23   } else {
24     *path = 0;
25     ierr = PetscStrallocpy(name,function);CHKERRQ(ierr);
26   }
27   PetscFunctionReturn(0);
28 }
29 
30 /*
31     This is the default list used by PETSc with the PetscDLLibrary register routines
32 */
33 PetscDLLibrary DLLibrariesLoaded = 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,&DLLibrariesLoaded,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,&DLLibrariesLoaded,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,&DLLibrariesLoaded,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,&DLLibrariesLoaded,libname[i]);CHKERRQ(ierr);
125     ierr = PetscDLLibraryCCAAppend(PETSC_COMM_WORLD,&DLLibrariesLoaded,libname[i]);CHKERRQ(ierr);
126     ierr = PetscFree(libname[i]);CHKERRQ(ierr);
127   }
128 
129   PetscFunctionReturn(0);
130 }
131 
132 #undef __FUNCT__
133 #define __FUNCT__ "PetscFinalize_DynamicLibraries"
134 /*
135      PetscFinalize_DynamicLibraries - Closes the opened dynamic libraries.
136 */
137 PetscErrorCode PetscFinalize_DynamicLibraries(void)
138 {
139   PetscErrorCode ierr;
140   PetscBool      flg = PETSC_FALSE;
141 
142   PetscFunctionBegin;
143   ierr = PetscOptionsGetBool(PETSC_NULL,"-dll_view",&flg,PETSC_NULL);CHKERRQ(ierr);
144   if (flg) { ierr = PetscDLLibraryPrintPath(DLLibrariesLoaded);CHKERRQ(ierr); }
145   ierr = PetscDLLibraryClose(DLLibrariesLoaded);CHKERRQ(ierr);
146   DLLibrariesLoaded = 0;
147   PetscFunctionReturn(0);
148 }
149 
150 /* ------------------------------------------------------------------------------*/
151 struct _n_PetscFList {
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   PetscFList  next;               /* next pointer */
157   PetscFList  next_list;          /* used to maintain list of all lists for freeing */
158 };
159 
160 /*
161      Keep a linked list of PetscFLists so that we can destroy all the left-over ones.
162 */
163 static PetscFList   dlallhead = 0;
164 
165 #undef __FUNCT__
166 #define __FUNCT__ "PetscFListAdd"
167 /*@C
168    PetscFListAddDynamic - Given a routine and a string id, saves that routine in the
169    specified registry.
170 
171      Not Collective
172 
173    Input Parameters:
174 +  fl    - pointer registry
175 .  name  - string to identify routine
176 .  rname - routine name in dynamic library
177 -  fnc   - function pointer (optional if using dynamic libraries)
178 
179    Notes:
180    To remove a registered routine, pass in a PETSC_NULL rname and fnc().
181 
182    Users who wish to register new classes for use by a particular PETSc
183    component (e.g., SNES) should generally call the registration routine
184    for that particular component (e.g., SNESRegisterDynamic()) instead of
185    calling PetscFListAddDynamic() directly.
186 
187    ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, or ${any environmental variable}
188   occuring in pathname will be replaced with appropriate values.
189 
190    Level: developer
191 
192 .seealso: PetscFListDestroy(), SNESRegisterDynamic(), KSPRegisterDynamic(),
193           PCRegisterDynamic(), TSRegisterDynamic(), PetscFList
194 @*/
195 PetscErrorCode  PetscFListAdd(PetscFList *fl,const char name[],const char rname[],void (*fnc)(void))
196 {
197   PetscFList     entry,ne;
198   PetscErrorCode ierr;
199   char           *fpath,*fname;
200 
201   PetscFunctionBegin;
202   if (!*fl) {
203     ierr           = PetscNew(struct _n_PetscFList,&entry);CHKERRQ(ierr);
204     ierr           = PetscStrallocpy(name,&entry->name);CHKERRQ(ierr);
205     ierr           = PetscFListGetPathAndFunction(rname,&fpath,&fname);CHKERRQ(ierr);
206     entry->path    = fpath;
207     entry->rname   = fname;
208     entry->routine = fnc;
209     entry->next    = 0;
210     *fl = entry;
211 
212     /* add this new list to list of all lists */
213     if (!dlallhead) {
214       dlallhead        = *fl;
215       (*fl)->next_list = 0;
216     } else {
217       ne               = dlallhead;
218       dlallhead        = *fl;
219       (*fl)->next_list = ne;
220     }
221   } else {
222     /* search list to see if it is already there */
223     ne = *fl;
224     while (ne) {
225       PetscBool  founddup;
226 
227       ierr = PetscStrcmp(ne->name,name,&founddup);CHKERRQ(ierr);
228       if (founddup) { /* found duplicate */
229         ierr = PetscFListGetPathAndFunction(rname,&fpath,&fname);CHKERRQ(ierr);
230         ierr = PetscFree(ne->path);CHKERRQ(ierr);
231         ierr = PetscFree(ne->rname);CHKERRQ(ierr);
232         ne->path    = fpath;
233         ne->rname   = fname;
234         ne->routine = fnc;
235         PetscFunctionReturn(0);
236       }
237       if (ne->next) ne = ne->next; else break;
238     }
239     /* create new entry and add to end of list */
240     ierr           = PetscNew(struct _n_PetscFList,&entry);CHKERRQ(ierr);
241     ierr           = PetscStrallocpy(name,&entry->name);CHKERRQ(ierr);
242     ierr           = PetscFListGetPathAndFunction(rname,&fpath,&fname);CHKERRQ(ierr);
243     entry->path    = fpath;
244     entry->rname   = fname;
245     entry->routine = fnc;
246     entry->next    = 0;
247     ne->next       = entry;
248   }
249   PetscFunctionReturn(0);
250 }
251 
252 #undef __FUNCT__
253 #define __FUNCT__ "PetscFListDestroy"
254 /*@
255     PetscFListDestroy - Destroys a list of registered routines.
256 
257     Input Parameter:
258 .   fl  - pointer to list
259 
260     Level: developer
261 
262 .seealso: PetscFListAddDynamic(), PetscFList
263 @*/
264 PetscErrorCode  PetscFListDestroy(PetscFList *fl)
265 {
266   PetscFList     next,entry,tmp = dlallhead;
267   PetscErrorCode ierr;
268 
269   PetscFunctionBegin;
270   if (!*fl) PetscFunctionReturn(0);
271   if (!dlallhead) PetscFunctionReturn(0);
272 
273   /*
274        Remove this entry from the master DL list (if it is in it)
275   */
276   if (dlallhead == *fl) {
277     if (dlallhead->next_list) {
278       dlallhead = dlallhead->next_list;
279     } else {
280       dlallhead = 0;
281     }
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__ "PetscFListDestroyAll"
309 PetscErrorCode  PetscFListDestroyAll(void)
310 {
311   PetscFList     tmp2,tmp1 = dlallhead;
312   PetscErrorCode ierr;
313 
314   PetscFunctionBegin;
315   while (tmp1) {
316     tmp2 = tmp1->next_list;
317     ierr = PetscFListDestroy(&tmp1);CHKERRQ(ierr);
318     tmp1 = tmp2;
319   }
320   dlallhead = 0;
321   PetscFunctionReturn(0);
322 }
323 
324 #undef __FUNCT__
325 #define __FUNCT__ "PetscFListFind"
326 /*@C
327     PetscFListFind - 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: PetscFListAddDynamic(), PetscFList
341 @*/
342 PetscErrorCode  PetscFListFind(PetscFList fl,MPI_Comm comm,const char name[],PetscBool searchlibraries,void (**r)(void))
343 {
344   PetscFList     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 = PetscFListGetPathAndFunction(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,&DLLibrariesLoaded,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,&DLLibrariesLoaded,newpath,entry->rname,(void **)r);CHKERRQ(ierr);
409       if (*r) {
410         entry->routine = *r;
411         ierr = PetscFree(path);CHKERRQ(ierr);
412         ierr = PetscFree(function);CHKERRQ(ierr);
413         PetscFunctionReturn(0);
414       }
415 #endif
416     }
417     entry = entry->next;
418   }
419 
420 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES)
421   if (searchlibraries) {
422     /* Function never registered; try for it anyway */
423     ierr = PetscDLLibrarySym(comm,&DLLibrariesLoaded,path,function,(void **)r);CHKERRQ(ierr);
424     ierr = PetscFree(path);CHKERRQ(ierr);
425     if (*r) {
426       ierr = PetscFListAdd(&fl,name,name,*r);CHKERRQ(ierr);
427     }
428   }
429 #endif
430   ierr = PetscFree(function);CHKERRQ(ierr);
431   PetscFunctionReturn(0);
432 }
433 
434 #undef __FUNCT__
435 #define __FUNCT__ "PetscFListView"
436 /*@
437    PetscFListView - prints out contents of an PetscFList
438 
439    Collective over MPI_Comm
440 
441    Input Parameters:
442 +  list - the list of functions
443 -  viewer - currently ignored
444 
445    Level: developer
446 
447 .seealso: PetscFListAddDynamic(), PetscFListPrintTypes(), PetscFList
448 @*/
449 PetscErrorCode  PetscFListView(PetscFList list,PetscViewer viewer)
450 {
451   PetscErrorCode ierr;
452   PetscBool      iascii;
453 
454   PetscFunctionBegin;
455   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;
456   PetscValidPointer(list,1);
457   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
458 
459   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
460   if (!iascii) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Only ASCII viewer supported");
461 
462   while (list) {
463     if (list->path) {
464       ierr = PetscViewerASCIIPrintf(viewer," %s %s %s\n",list->path,list->name,list->rname);CHKERRQ(ierr);
465     } else {
466       ierr = PetscViewerASCIIPrintf(viewer," %s %s\n",list->name,list->rname);CHKERRQ(ierr);
467     }
468     list = list->next;
469   }
470   ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
471   PetscFunctionReturn(0);
472 }
473 
474 #undef __FUNCT__
475 #define __FUNCT__ "PetscFListGet"
476 /*@
477    PetscFListGet - Gets an array the contains the entries in PetscFList, this is used
478          by help etc.
479 
480    Collective over MPI_Comm
481 
482    Input Parameter:
483 .  list   - list of types
484 
485    Output Parameter:
486 +  array - array of names
487 -  n - length of array
488 
489    Notes:
490        This allocates the array so that must be freed. BUT the individual entries are
491     not copied so should not be freed.
492 
493    Level: developer
494 
495 .seealso: PetscFListAddDynamic(), PetscFList
496 @*/
497 PetscErrorCode  PetscFListGet(PetscFList list,char ***array,int *n)
498 {
499   PetscErrorCode ierr;
500   PetscInt       count = 0;
501   PetscFList     klist = list;
502 
503   PetscFunctionBegin;
504   while (list) {
505     list = list->next;
506     count++;
507   }
508   ierr  = PetscMalloc((count+1)*sizeof(char *),array);CHKERRQ(ierr);
509   count = 0;
510   while (klist) {
511     (*array)[count] = klist->name;
512     klist = klist->next;
513     count++;
514   }
515   (*array)[count] = 0;
516   *n = count+1;
517   PetscFunctionReturn(0);
518 }
519 
520 
521 #undef __FUNCT__
522 #define __FUNCT__ "PetscFListPrintTypes"
523 /*@C
524    PetscFListPrintTypes - Prints the methods available.
525 
526    Collective over MPI_Comm
527 
528    Input Parameters:
529 +  comm   - the communicator (usually MPI_COMM_WORLD)
530 .  fd     - file to print to, usually stdout
531 .  prefix - prefix to prepend to name (optional)
532 .  name   - option string (for example, "-ksp_type")
533 .  text - short description of the object (for example, "Krylov solvers")
534 .  man - name of manual page that discusses the object (for example, "KSPCreate")
535 .  list   - list of types
536 -  def - default (current) value
537 
538    Level: developer
539 
540 .seealso: PetscFListAddDynamic(), PetscFList
541 @*/
542 PetscErrorCode  PetscFListPrintTypes(MPI_Comm comm,FILE *fd,const char prefix[],const char name[],const char text[],const char man[],PetscFList list,const char def[])
543 {
544   PetscErrorCode ierr;
545   PetscInt       count = 0;
546   char           p[64];
547 
548   PetscFunctionBegin;
549   if (!fd) fd = PETSC_STDOUT;
550 
551   ierr = PetscStrcpy(p,"-");CHKERRQ(ierr);
552   if (prefix) {ierr = PetscStrcat(p,prefix);CHKERRQ(ierr);}
553   ierr = PetscFPrintf(comm,fd,"  %s%s <%s>: %s (one of)",p,name+1,def,text);CHKERRQ(ierr);
554 
555   while (list) {
556     ierr = PetscFPrintf(comm,fd," %s",list->name);CHKERRQ(ierr);
557     list = list->next;
558     count++;
559     if (count == 8) {ierr = PetscFPrintf(comm,fd,"\n     ");CHKERRQ(ierr);}
560   }
561   ierr = PetscFPrintf(comm,fd," (%s)\n",man);CHKERRQ(ierr);
562   PetscFunctionReturn(0);
563 }
564 
565 #undef __FUNCT__
566 #define __FUNCT__ "PetscFListDuplicate"
567 /*@
568     PetscFListDuplicate - Creates a new list from a given object list.
569 
570     Input Parameters:
571 .   fl   - pointer to list
572 
573     Output Parameters:
574 .   nl - the new list (should point to 0 to start, otherwise appends)
575 
576     Level: developer
577 
578 .seealso: PetscFList, PetscFListAdd(), PetscFlistDestroy()
579 
580 @*/
581 PetscErrorCode  PetscFListDuplicate(PetscFList fl,PetscFList *nl)
582 {
583   PetscErrorCode ierr;
584   char           path[PETSC_MAX_PATH_LEN];
585 
586   PetscFunctionBegin;
587   while (fl) {
588     /* this is silly, rebuild the complete pathname */
589     if (fl->path) {
590       ierr = PetscStrcpy(path,fl->path);CHKERRQ(ierr);
591       ierr = PetscStrcat(path,":");CHKERRQ(ierr);
592       ierr = PetscStrcat(path,fl->name);CHKERRQ(ierr);
593     } else {
594       ierr = PetscStrcpy(path,fl->name);CHKERRQ(ierr);
595     }
596     ierr = PetscFListAdd(nl,path,fl->rname,fl->routine);CHKERRQ(ierr);
597     fl   = fl->next;
598   }
599   PetscFunctionReturn(0);
600 }
601 
602 
603 #undef __FUNCT__
604 #define __FUNCT__ "PetscFListConcat"
605 /*
606     PetscFListConcat - joins name of a libary, and the path where it is located
607     into a single string.
608 
609     Input Parameters:
610 .   path   - path to the library name.
611 .   name   - name of the library
612 
613     Output Parameters:
614 .   fullname - the name that is the union of the path and the library name,
615                delimited by a semicolon, i.e., path:name
616 
617     Notes:
618     If the path is NULL, assumes that the name, specified also includes
619     the path as path:name
620 
621 */
622 PetscErrorCode  PetscFListConcat(const char path[],const char name[],char fullname[])
623 {
624   PetscErrorCode ierr;
625   PetscFunctionBegin;
626   if (path) {
627     ierr = PetscStrcpy(fullname,path);CHKERRQ(ierr);
628     ierr = PetscStrcat(fullname,":");CHKERRQ(ierr);
629     ierr = PetscStrcat(fullname,name);CHKERRQ(ierr);
630   } else {
631     ierr = PetscStrcpy(fullname,name);CHKERRQ(ierr);
632   }
633   PetscFunctionReturn(0);
634 }
635