xref: /petsc/src/sys/dll/reg.c (revision 28adb3f739167aae2a3fdf9bf501dbd0150de1de)
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 /*
31     This is the default list used by PETSc with the PetscDLLibrary register routines
32 */
33 PetscDLLibrary DLLibrariesLoaded = 0;
34 
35 
36 #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
37 
38 #undef __FUNCT__
39 #define __FUNCT__ "PetscLoadDynamicLibrary"
40 static PetscErrorCode PETSC_DLLEXPORT PetscLoadDynamicLibrary(const char *name,PetscTruth *found)
41 {
42   char           libs[PETSC_MAX_PATH_LEN],dlib[PETSC_MAX_PATH_LEN];
43   PetscErrorCode ierr;
44 
45   PetscFunctionBegin;
46   ierr = PetscStrcpy(libs,"${PETSC_LIB_DIR}/libpetsc");CHKERRQ(ierr);
47   ierr = PetscStrcat(libs,name);CHKERRQ(ierr);
48   ierr = PetscDLLibraryRetrieve(PETSC_COMM_WORLD,libs,dlib,1024,found);CHKERRQ(ierr);
49   if (*found) {
50     ierr = PetscDLLibraryAppend(PETSC_COMM_WORLD,&DLLibrariesLoaded,dlib);CHKERRQ(ierr);
51   } else {
52     ierr = PetscStrcpy(libs,"${PETSC_DIR}/${PETSC_ARCH}/lib/libpetsc");CHKERRQ(ierr);
53     ierr = PetscStrcat(libs,name);CHKERRQ(ierr);
54     ierr = PetscDLLibraryRetrieve(PETSC_COMM_WORLD,libs,dlib,1024,found);CHKERRQ(ierr);
55     if (*found) {
56       ierr = PetscDLLibraryAppend(PETSC_COMM_WORLD,&DLLibrariesLoaded,dlib);CHKERRQ(ierr);
57     }
58   }
59   PetscFunctionReturn(0);
60 }
61 
62 #endif
63 
64 #undef __FUNCT__
65 #define __FUNCT__ "PetscInitialize_DynamicLibraries"
66 /*
67     PetscInitialize_DynamicLibraries - Adds the default dynamic link libraries to the
68     search path.
69 */
70 PetscErrorCode PETSC_DLLEXPORT PetscInitialize_DynamicLibraries(void)
71 {
72   char           *libname[32];
73   PetscErrorCode ierr;
74   PetscInt       nmax,i;
75 #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
76   PetscTruth     found;
77 #endif
78   PetscFunctionBegin;
79 
80   nmax = 32;
81   ierr = PetscOptionsGetStringArray(PETSC_NULL,"-dll_prepend",libname,&nmax,PETSC_NULL);CHKERRQ(ierr);
82   for (i=0; i<nmax; i++) {
83     ierr = PetscDLLibraryPrepend(PETSC_COMM_WORLD,&DLLibrariesLoaded,libname[i]);CHKERRQ(ierr);
84     ierr = PetscFree(libname[i]);CHKERRQ(ierr);
85   }
86 
87 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
88   /*
89       This just initializes the most basic PETSc stuff.
90 
91     The classes, from PetscDraw to PetscTS, are initialized the first
92     time an XXCreate() is called.
93   */
94   ierr = PetscInitializePackage(PETSC_NULL);CHKERRQ(ierr);
95 #else
96   ierr = PetscLoadDynamicLibrary("",&found);CHKERRQ(ierr);
97   if (!found) SETERRQ(PETSC_ERR_FILE_OPEN,"Unable to locate PETSc dynamic library \n You cannot move the dynamic libraries!");
98 #if !defined(PETSC_USE_SINGLE_LIBRARY)
99   ierr = PetscLoadDynamicLibrary("vec",&found);CHKERRQ(ierr);
100   if (!found) SETERRQ(PETSC_ERR_FILE_OPEN,"Unable to locate PETSc Vec dynamic library \n You cannot move the dynamic libraries!");
101   ierr = PetscLoadDynamicLibrary("mat",&found);CHKERRQ(ierr);
102   if (!found) SETERRQ(PETSC_ERR_FILE_OPEN,"Unable to locate PETSc Mat dynamic library \n You cannot move the dynamic libraries!");
103   ierr = PetscLoadDynamicLibrary("dm",&found);CHKERRQ(ierr);
104   if (!found) SETERRQ(PETSC_ERR_FILE_OPEN,"Unable to locate PETSc DM dynamic library \n You cannot move the dynamic libraries!");
105   ierr = PetscLoadDynamicLibrary("ksp",&found);CHKERRQ(ierr);
106   if (!found) SETERRQ(PETSC_ERR_FILE_OPEN,"Unable to locate PETSc KSP dynamic library \n You cannot move the dynamic libraries!");
107   ierr = PetscLoadDynamicLibrary("snes",&found);CHKERRQ(ierr);
108   if (!found) SETERRQ(PETSC_ERR_FILE_OPEN,"Unable to locate PETSc SNES dynamic library \n You cannot move the dynamic libraries!");
109   ierr = PetscLoadDynamicLibrary("ts",&found);CHKERRQ(ierr);
110   if (!found) SETERRQ(PETSC_ERR_FILE_OPEN,"Unable to locate PETSc TS dynamic library \n You cannot move the dynamic libraries!");
111 #endif
112 
113   ierr = PetscLoadDynamicLibrary("mesh",&found);CHKERRQ(ierr);
114   ierr = PetscLoadDynamicLibrary("contrib",&found);CHKERRQ(ierr);
115 #endif
116 
117   nmax = 32;
118   ierr = PetscOptionsGetStringArray(PETSC_NULL,"-dll_append",libname,&nmax,PETSC_NULL);CHKERRQ(ierr);
119   for (i=0; i<nmax; i++) {
120     ierr = PetscDLLibraryAppend(PETSC_COMM_WORLD,&DLLibrariesLoaded,libname[i]);CHKERRQ(ierr);
121     ierr = PetscDLLibraryCCAAppend(PETSC_COMM_WORLD,&DLLibrariesLoaded,libname[i]);CHKERRQ(ierr);
122     ierr = PetscFree(libname[i]);CHKERRQ(ierr);
123   }
124 
125   PetscFunctionReturn(0);
126 }
127 
128 #undef __FUNCT__
129 #define __FUNCT__ "PetscFinalize_DynamicLibraries"
130 /*
131      PetscFinalize_DynamicLibraries - Closes the opened dynamic libraries.
132 */
133 PetscErrorCode PetscFinalize_DynamicLibraries(void)
134 {
135   PetscErrorCode ierr;
136   PetscTruth     flg = PETSC_FALSE;
137 
138   PetscFunctionBegin;
139   ierr = PetscOptionsGetTruth(PETSC_NULL,"-dll_view",&flg,PETSC_NULL);CHKERRQ(ierr);
140   if (flg) { ierr = PetscDLLibraryPrintPath(DLLibrariesLoaded);CHKERRQ(ierr); }
141   ierr = PetscDLLibraryClose(DLLibrariesLoaded);CHKERRQ(ierr);
142   DLLibrariesLoaded = 0;
143   PetscFunctionReturn(0);
144 }
145 
146 /* ------------------------------------------------------------------------------*/
147 struct _n_PetscFList {
148   void        (*routine)(void);   /* the routine */
149   char        *path;              /* path of link library containing routine */
150   char        *name;              /* string to identify routine */
151   char        *rname;             /* routine name in dynamic library */
152   PetscFList  next;               /* next pointer */
153   PetscFList  next_list;          /* used to maintain list of all lists for freeing */
154 };
155 
156 /*
157      Keep a linked list of PetscFLists so that we can destroy all the left-over ones.
158 */
159 static PetscFList   dlallhead = 0;
160 
161 #undef __FUNCT__
162 #define __FUNCT__ "PetscFListAdd"
163 /*@C
164    PetscFListAddDynamic - Given a routine and a string id, saves that routine in the
165    specified registry.
166 
167      Not Collective
168 
169    Input Parameters:
170 +  fl    - pointer registry
171 .  name  - string to identify routine
172 .  rname - routine name in dynamic library
173 -  fnc   - function pointer (optional if using dynamic libraries)
174 
175    Notes:
176    To remove a registered routine, pass in a PETSC_NULL rname and fnc().
177 
178    Users who wish to register new classes for use by a particular PETSc
179    component (e.g., SNES) should generally call the registration routine
180    for that particular component (e.g., SNESRegisterDynamic()) instead of
181    calling PetscFListAddDynamic() directly.
182 
183    ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, or ${any environmental variable}
184   occuring in pathname will be replaced with appropriate values.
185 
186    Level: developer
187 
188 .seealso: PetscFListDestroy(), SNESRegisterDynamic(), KSPRegisterDynamic(),
189           PCRegisterDynamic(), TSRegisterDynamic(), PetscFList
190 @*/
191 PetscErrorCode PETSC_DLLEXPORT PetscFListAdd(PetscFList *fl,const char name[],const char rname[],void (*fnc)(void))
192 {
193   PetscFList     entry,ne;
194   PetscErrorCode ierr;
195   char           *fpath,*fname;
196 
197   PetscFunctionBegin;
198 
199   if (!*fl) {
200     ierr           = PetscNew(struct _n_PetscFList,&entry);CHKERRQ(ierr);
201     ierr           = PetscStrallocpy(name,&entry->name);CHKERRQ(ierr);
202     ierr           = PetscFListGetPathAndFunction(rname,&fpath,&fname);CHKERRQ(ierr);
203     entry->path    = fpath;
204     entry->rname   = fname;
205     entry->routine = fnc;
206     entry->next    = 0;
207     *fl = entry;
208 
209     /* add this new list to list of all lists */
210     if (!dlallhead) {
211       dlallhead        = *fl;
212       (*fl)->next_list = 0;
213     } else {
214       ne               = dlallhead;
215       dlallhead        = *fl;
216       (*fl)->next_list = ne;
217     }
218   } else {
219     /* search list to see if it is already there */
220     ne = *fl;
221     while (ne) {
222       PetscTruth founddup;
223 
224       ierr = PetscStrcmp(ne->name,name,&founddup);CHKERRQ(ierr);
225       if (founddup) { /* found duplicate */
226         ierr = PetscFListGetPathAndFunction(rname,&fpath,&fname);CHKERRQ(ierr);
227         ierr = PetscStrfree(ne->path);CHKERRQ(ierr);
228         ierr = PetscStrfree(ne->rname);CHKERRQ(ierr);
229         ne->path    = fpath;
230         ne->rname   = fname;
231         ne->routine = fnc;
232         PetscFunctionReturn(0);
233       }
234       if (ne->next) ne = ne->next; else break;
235     }
236     /* create new entry and add to end of list */
237     ierr           = PetscNew(struct _n_PetscFList,&entry);CHKERRQ(ierr);
238     ierr           = PetscStrallocpy(name,&entry->name);CHKERRQ(ierr);
239     ierr           = PetscFListGetPathAndFunction(rname,&fpath,&fname);CHKERRQ(ierr);
240     entry->path    = fpath;
241     entry->rname   = fname;
242     entry->routine = fnc;
243     entry->next    = 0;
244     ne->next       = entry;
245   }
246 
247   PetscFunctionReturn(0);
248 }
249 
250 #undef __FUNCT__
251 #define __FUNCT__ "PetscFListDestroy"
252 /*@
253     PetscFListDestroy - Destroys a list of registered routines.
254 
255     Input Parameter:
256 .   fl  - pointer to list
257 
258     Level: developer
259 
260 .seealso: PetscFListAddDynamic(), PetscFList
261 @*/
262 PetscErrorCode PETSC_DLLEXPORT PetscFListDestroy(PetscFList *fl)
263 {
264   PetscFList     next,entry,tmp = dlallhead;
265   PetscErrorCode ierr;
266 
267   PetscFunctionBegin;
268   CHKMEMQ;
269   if (!*fl) PetscFunctionReturn(0);
270 
271   if (!dlallhead) {
272     PetscFunctionReturn(0);
273   }
274 
275   /*
276        Remove this entry from the master DL list (if it is in it)
277   */
278   if (dlallhead == *fl) {
279     if (dlallhead->next_list) {
280       dlallhead = dlallhead->next_list;
281     } else {
282       dlallhead = 0;
283     }
284   } else {
285     while (tmp->next_list != *fl) {
286       tmp = tmp->next_list;
287       if (!tmp->next_list) break;
288     }
289     if (tmp->next_list) tmp->next_list = tmp->next_list->next_list;
290   }
291 
292   /* free this list */
293   entry = *fl;
294   while (entry) {
295     next = entry->next;
296     ierr = PetscStrfree(entry->path);CHKERRQ(ierr);
297     ierr = PetscFree(entry->name);CHKERRQ(ierr);
298     ierr = PetscFree(entry->rname);CHKERRQ(ierr);
299     ierr = PetscFree(entry);CHKERRQ(ierr);
300     entry = next;
301   }
302   *fl = 0;
303   PetscFunctionReturn(0);
304 }
305 
306 /*
307    Destroys all the function lists that anyone has every registered, such as KSPList, VecList, etc.
308 */
309 #undef __FUNCT__
310 #define __FUNCT__ "PetscFListDestroyAll"
311 PetscErrorCode PETSC_DLLEXPORT PetscFListDestroyAll(void)
312 {
313   PetscFList     tmp2,tmp1 = dlallhead;
314   PetscErrorCode ierr;
315 
316   PetscFunctionBegin;
317   while (tmp1) {
318     tmp2 = tmp1->next_list;
319     ierr = PetscFListDestroy(&tmp1);CHKERRQ(ierr);
320     tmp1 = tmp2;
321   }
322   dlallhead = 0;
323   PetscFunctionReturn(0);
324 }
325 
326 #undef __FUNCT__
327 #define __FUNCT__ "PetscFListFind"
328 /*@C
329     PetscFListFind - Given a name, finds the matching routine.
330 
331     Input Parameters:
332 +   fl   - pointer to list
333 .   comm - processors looking for routine
334 -   name - name string
335 
336     Output Parameters:
337 .   r - the routine
338 
339     Level: developer
340 
341 .seealso: PetscFListAddDynamic(), PetscFList
342 @*/
343 PetscErrorCode PETSC_DLLEXPORT PetscFListFind(PetscFList fl,MPI_Comm comm,const char name[],void (**r)(void))
344 {
345   PetscFList     entry = fl;
346   PetscErrorCode ierr;
347   char           *function,*path;
348 #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
349   char           *newpath;
350 #endif
351   PetscTruth   flg,f1,f2,f3;
352 
353   PetscFunctionBegin;
354   if (!name) SETERRQ(PETSC_ERR_ARG_NULL,"Trying to find routine with null name");
355 
356   *r = 0;
357   ierr = PetscFListGetPathAndFunction(name,&path,&function);CHKERRQ(ierr);
358 
359   /*
360         If path then append it to search libraries
361   */
362 #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
363   if (path) {
364     ierr = PetscDLLibraryAppend(comm,&DLLibrariesLoaded,path);CHKERRQ(ierr);
365   }
366 #endif
367 
368   while (entry) {
369     flg = PETSC_FALSE;
370     if (path && entry->path) {
371       ierr = PetscStrcmp(path,entry->path,&f1);CHKERRQ(ierr);
372       ierr = PetscStrcmp(function,entry->rname,&f2);CHKERRQ(ierr);
373       ierr = PetscStrcmp(function,entry->name,&f3);CHKERRQ(ierr);
374       flg =  (PetscTruth) ((f1 && f2) || (f1 && f3));
375     } else if (!path) {
376       ierr = PetscStrcmp(function,entry->name,&f1);CHKERRQ(ierr);
377       ierr = PetscStrcmp(function,entry->rname,&f2);CHKERRQ(ierr);
378       flg =  (PetscTruth) (f1 || f2);
379     } else {
380       ierr = PetscStrcmp(function,entry->name,&flg);CHKERRQ(ierr);
381       if (flg) {
382         ierr = PetscFree(function);CHKERRQ(ierr);
383         ierr = PetscStrallocpy(entry->rname,&function);CHKERRQ(ierr);
384       } else {
385         ierr = PetscStrcmp(function,entry->rname,&flg);CHKERRQ(ierr);
386       }
387     }
388 
389     if (flg) {
390 
391       if (entry->routine) {
392         *r   = entry->routine;
393         ierr = PetscStrfree(path);CHKERRQ(ierr);
394         ierr = PetscFree(function);CHKERRQ(ierr);
395         PetscFunctionReturn(0);
396       }
397 
398       if ((path && entry->path && f3) || (!path && f1)) { /* convert name of function (alias) to actual function name */
399         ierr = PetscFree(function);CHKERRQ(ierr);
400         ierr = PetscStrallocpy(entry->rname,&function);CHKERRQ(ierr);
401       }
402 
403       /* it is not yet in memory so load from dynamic library */
404 #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
405       newpath = path;
406       if (!path) newpath = entry->path;
407       ierr = PetscDLLibrarySym(comm,&DLLibrariesLoaded,newpath,entry->rname,(void **)r);CHKERRQ(ierr);
408       if (*r) {
409         entry->routine = *r;
410         ierr = PetscStrfree(path);CHKERRQ(ierr);
411         ierr = PetscFree(function);CHKERRQ(ierr);
412         PetscFunctionReturn(0);
413       } else {
414         PetscErrorPrintf("Unable to find function. Search path:\n");
415         ierr = PetscDLLibraryPrintPath(DLLibrariesLoaded);CHKERRQ(ierr);
416         SETERRQ1(PETSC_ERR_PLIB,"Unable to find function:%s: either it is mis-spelled or dynamic library is not in path",entry->rname);
417       }
418 #endif
419     }
420     entry = entry->next;
421   }
422 
423 #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
424   /* Function never registered; try for it anyway */
425   ierr = PetscDLLibrarySym(comm,&DLLibrariesLoaded,path,function,(void **)r);CHKERRQ(ierr);
426   ierr = PetscStrfree(path);CHKERRQ(ierr);
427   if (*r) {
428     ierr = PetscFListAdd(&fl,name,name,*r);CHKERRQ(ierr);
429   }
430 #endif
431   ierr = PetscFree(function);CHKERRQ(ierr);
432   PetscFunctionReturn(0);
433 }
434 
435 #undef __FUNCT__
436 #define __FUNCT__ "PetscFListView"
437 /*@
438    PetscFListView - prints out contents of an PetscFList
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: PetscFListAddDynamic(), PetscFListPrintTypes(), PetscFList
449 @*/
450 PetscErrorCode PETSC_DLLEXPORT PetscFListView(PetscFList list,PetscViewer viewer)
451 {
452   PetscErrorCode ierr;
453   PetscTruth     iascii;
454 
455   PetscFunctionBegin;
456   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;
457   PetscValidPointer(list,1);
458   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_COOKIE,2);
459 
460   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr);
461   if (!iascii) SETERRQ(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__ "PetscFListGet"
477 /*@
478    PetscFListGet - Gets an array the contains the entries in PetscFList, 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: PetscFListAddDynamic(), PetscFList
497 @*/
498 PetscErrorCode PETSC_DLLEXPORT PetscFListGet(PetscFList list,char ***array,int *n)
499 {
500   PetscErrorCode ierr;
501   PetscInt       count = 0;
502   PetscFList     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 
519   PetscFunctionReturn(0);
520 }
521 
522 
523 #undef __FUNCT__
524 #define __FUNCT__ "PetscFListPrintTypes"
525 /*@C
526    PetscFListPrintTypes - Prints the methods available.
527 
528    Collective over MPI_Comm
529 
530    Input Parameters:
531 +  comm   - the communicator (usually MPI_COMM_WORLD)
532 .  fd     - file to print to, usually stdout
533 .  prefix - prefix to prepend to name (optional)
534 .  name   - option string (for example, "-ksp_type")
535 .  text - short description of the object (for example, "Krylov solvers")
536 .  man - name of manual page that discusses the object (for example, "KSPCreate")
537 -  list   - list of types
538 
539    Level: developer
540 
541 .seealso: PetscFListAddDynamic(), PetscFList
542 @*/
543 PetscErrorCode PETSC_DLLEXPORT PetscFListPrintTypes(PetscFList list,MPI_Comm comm,FILE *fd,const char prefix[],const char name[],const char text[],const char man[])
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:(one of)",p,name+1,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__ "PetscFListDuplicate"
568 /*@
569     PetscFListDuplicate - 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: PetscFList, PetscFListAdd(), PetscFlistDestroy()
580 
581 @*/
582 PetscErrorCode PETSC_DLLEXPORT PetscFListDuplicate(PetscFList fl,PetscFList *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 = PetscFListAdd(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__ "PetscFListConcat"
606 /*
607     PetscFListConcat - 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 PETSC_DLLEXPORT PetscFListConcat(const char path[],const char name[],char fullname[])
624 {
625   PetscErrorCode ierr;
626   PetscFunctionBegin;
627   if (path) {
628     ierr = PetscStrcpy(fullname,path);CHKERRQ(ierr);
629     ierr = PetscStrcat(fullname,":");CHKERRQ(ierr);
630     ierr = PetscStrcat(fullname,name);CHKERRQ(ierr);
631   } else {
632     ierr = PetscStrcpy(fullname,name);CHKERRQ(ierr);
633   }
634   PetscFunctionReturn(0);
635 }
636