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