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