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