xref: /petsc/src/sys/dll/reg.c (revision 3fa76a5b188a02dd677974deca162194da798f66)
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   ierr = PetscLoadDynamicLibrary("vec",&found);CHKERRQ(ierr);
99   if (!found) SETERRQ(PETSC_ERR_FILE_OPEN,"Unable to locate PETSc Vec dynamic library \n You cannot move the dynamic libraries!");
100   ierr = PetscLoadDynamicLibrary("mat",&found);CHKERRQ(ierr);
101   if (!found) SETERRQ(PETSC_ERR_FILE_OPEN,"Unable to locate PETSc Mat dynamic library \n You cannot move the dynamic libraries!");
102   ierr = PetscLoadDynamicLibrary("dm",&found);CHKERRQ(ierr);
103   if (!found) SETERRQ(PETSC_ERR_FILE_OPEN,"Unable to locate PETSc DM dynamic library \n You cannot move the dynamic libraries!");
104   ierr = PetscLoadDynamicLibrary("ksp",&found);CHKERRQ(ierr);
105   if (!found) SETERRQ(PETSC_ERR_FILE_OPEN,"Unable to locate PETSc KSP dynamic library \n You cannot move the dynamic libraries!");
106   ierr = PetscLoadDynamicLibrary("snes",&found);CHKERRQ(ierr);
107   if (!found) SETERRQ(PETSC_ERR_FILE_OPEN,"Unable to locate PETSc SNES dynamic library \n You cannot move the dynamic libraries!");
108   ierr = PetscLoadDynamicLibrary("ts",&found);CHKERRQ(ierr);
109   if (!found) SETERRQ(PETSC_ERR_FILE_OPEN,"Unable to locate PETSc TS dynamic library \n You cannot move the dynamic libraries!");
110 
111   ierr = PetscLoadDynamicLibrary("mesh",&found);CHKERRQ(ierr);
112   ierr = PetscLoadDynamicLibrary("contrib",&found);CHKERRQ(ierr);
113 #endif
114 
115   nmax = 32;
116   ierr = PetscOptionsGetStringArray(PETSC_NULL,"-dll_append",libname,&nmax,PETSC_NULL);CHKERRQ(ierr);
117   for (i=0; i<nmax; i++) {
118     ierr = PetscDLLibraryAppend(PETSC_COMM_WORLD,&DLLibrariesLoaded,libname[i]);CHKERRQ(ierr);
119     ierr = PetscDLLibraryCCAAppend(PETSC_COMM_WORLD,&DLLibrariesLoaded,libname[i]);CHKERRQ(ierr);
120     ierr = PetscFree(libname[i]);CHKERRQ(ierr);
121   }
122 
123   PetscFunctionReturn(0);
124 }
125 
126 #undef __FUNCT__
127 #define __FUNCT__ "PetscFinalize_DynamicLibraries"
128 /*
129      PetscFinalize_DynamicLibraries - Closes the opened dynamic libraries.
130 */
131 PetscErrorCode PetscFinalize_DynamicLibraries(void)
132 {
133   PetscErrorCode ierr;
134   PetscTruth     flg;
135 
136   PetscFunctionBegin;
137   ierr = PetscOptionsHasName(PETSC_NULL,"-dll_view",&flg);CHKERRQ(ierr);
138   if (flg) { ierr = PetscDLLibraryPrintPath(DLLibrariesLoaded);CHKERRQ(ierr); }
139   ierr = PetscDLLibraryClose(&DLLibrariesLoaded);CHKERRQ(ierr);
140   PetscFunctionReturn(0);
141 }
142 
143 /* ------------------------------------------------------------------------------*/
144 struct _n_PetscFList {
145   void        (*routine)(void);   /* the routine */
146   char        *path;              /* path of link library containing routine */
147   char        *name;              /* string to identify routine */
148   char        *rname;             /* routine name in dynamic library */
149   PetscFList  next;               /* next pointer */
150   PetscFList  next_list;          /* used to maintain list of all lists for freeing */
151 };
152 
153 /*
154      Keep a linked list of PetscFLists so that we can destroy all the left-over ones.
155 */
156 static PetscFList   dlallhead = 0;
157 
158 #undef __FUNCT__
159 #define __FUNCT__ "PetscFListAdd"
160 /*@C
161    PetscFListAddDynamic - Given a routine and a string id, saves that routine in the
162    specified registry.
163 
164      Not Collective
165 
166    Input Parameters:
167 +  fl    - pointer registry
168 .  name  - string to identify routine
169 .  rname - routine name in dynamic library
170 -  fnc   - function pointer (optional if using dynamic libraries)
171 
172    Notes:
173    To remove a registered routine, pass in a PETSC_NULL rname and fnc().
174 
175    Users who wish to register new classes for use by a particular PETSc
176    component (e.g., SNES) should generally call the registration routine
177    for that particular component (e.g., SNESRegisterDynamic()) instead of
178    calling PetscFListAddDynamic() directly.
179 
180    ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, or ${any environmental variable}
181   occuring in pathname will be replaced with appropriate values.
182 
183    Level: developer
184 
185 .seealso: PetscFListDestroy(), SNESRegisterDynamic(), KSPRegisterDynamic(),
186           PCRegisterDynamic(), TSRegisterDynamic(), PetscFList
187 @*/
188 PetscErrorCode PETSC_DLLEXPORT PetscFListAdd(PetscFList *fl,const char name[],const char rname[],void (*fnc)(void))
189 {
190   PetscFList     entry,ne;
191   PetscErrorCode ierr;
192   char           *fpath,*fname;
193 
194   PetscFunctionBegin;
195 
196   if (!*fl) {
197     ierr           = PetscNew(struct _n_PetscFList,&entry);CHKERRQ(ierr);
198     ierr           = PetscStrallocpy(name,&entry->name);CHKERRQ(ierr);
199     ierr           = PetscFListGetPathAndFunction(rname,&fpath,&fname);CHKERRQ(ierr);
200     entry->path    = fpath;
201     entry->rname   = fname;
202     entry->routine = fnc;
203     entry->next    = 0;
204     *fl = entry;
205 
206     /* add this new list to list of all lists */
207     if (!dlallhead) {
208       dlallhead        = *fl;
209       (*fl)->next_list = 0;
210     } else {
211       ne               = dlallhead;
212       dlallhead        = *fl;
213       (*fl)->next_list = ne;
214     }
215   } else {
216     /* search list to see if it is already there */
217     ne = *fl;
218     while (ne) {
219       PetscTruth founddup;
220 
221       ierr = PetscStrcmp(ne->name,name,&founddup);CHKERRQ(ierr);
222       if (founddup) { /* found duplicate */
223         ierr = PetscFListGetPathAndFunction(rname,&fpath,&fname);CHKERRQ(ierr);
224         ierr = PetscStrfree(ne->path);CHKERRQ(ierr);
225         ierr = PetscStrfree(ne->rname);CHKERRQ(ierr);
226         ne->path    = fpath;
227         ne->rname   = fname;
228         ne->routine = fnc;
229         PetscFunctionReturn(0);
230       }
231       if (ne->next) ne = ne->next; else break;
232     }
233     /* create new entry and add to end of list */
234     ierr           = PetscNew(struct _n_PetscFList,&entry);CHKERRQ(ierr);
235     ierr           = PetscStrallocpy(name,&entry->name);CHKERRQ(ierr);
236     ierr           = PetscFListGetPathAndFunction(rname,&fpath,&fname);CHKERRQ(ierr);
237     entry->path    = fpath;
238     entry->rname   = fname;
239     entry->routine = fnc;
240     entry->next    = 0;
241     ne->next       = entry;
242   }
243 
244   PetscFunctionReturn(0);
245 }
246 
247 #undef __FUNCT__
248 #define __FUNCT__ "PetscFListDestroy"
249 /*@
250     PetscFListDestroy - Destroys a list of registered routines.
251 
252     Input Parameter:
253 .   fl  - pointer to list
254 
255     Level: developer
256 
257 .seealso: PetscFListAddDynamic(), PetscFList
258 @*/
259 PetscErrorCode PETSC_DLLEXPORT PetscFListDestroy(PetscFList *fl)
260 {
261   PetscFList     next,entry,tmp = dlallhead;
262   PetscErrorCode ierr;
263 
264   PetscFunctionBegin;
265   CHKMEMQ;
266   if (!*fl) PetscFunctionReturn(0);
267 
268   if (!dlallhead) {
269     PetscFunctionReturn(0);
270   }
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 = PetscStrfree(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 PETSC_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 PETSC_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 #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
346   char           *newpath;
347 #endif
348   PetscTruth   flg,f1,f2,f3;
349 
350   PetscFunctionBegin;
351   if (!name) SETERRQ(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_USE_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 =  (PetscTruth) ((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 =  (PetscTruth) (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 = PetscStrfree(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_USE_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 = PetscStrfree(path);CHKERRQ(ierr);
408         ierr = PetscFree(function);CHKERRQ(ierr);
409         PetscFunctionReturn(0);
410       } else {
411         PetscErrorPrintf("Unable to find function. Search path:\n");
412         ierr = PetscDLLibraryPrintPath(DLLibrariesLoaded);CHKERRQ(ierr);
413         SETERRQ1(PETSC_ERR_PLIB,"Unable to find function:%s: either it is mis-spelled or dynamic library is not in path",entry->rname);
414       }
415 #endif
416     }
417     entry = entry->next;
418   }
419 
420 #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
421   /* Function never registered; try for it anyway */
422   ierr = PetscDLLibrarySym(comm,&DLLibrariesLoaded,path,function,(void **)r);CHKERRQ(ierr);
423   ierr = PetscStrfree(path);CHKERRQ(ierr);
424   if (*r) {
425     ierr = PetscFListAdd(&fl,name,name,*r);CHKERRQ(ierr);
426   }
427 #endif
428   ierr = PetscFree(function);CHKERRQ(ierr);
429   PetscFunctionReturn(0);
430 }
431 
432 #undef __FUNCT__
433 #define __FUNCT__ "PetscFListView"
434 /*@
435    PetscFListView - prints out contents of an PetscFList
436 
437    Collective over MPI_Comm
438 
439    Input Parameters:
440 +  list - the list of functions
441 -  viewer - currently ignored
442 
443    Level: developer
444 
445 .seealso: PetscFListAddDynamic(), PetscFListPrintTypes(), PetscFList
446 @*/
447 PetscErrorCode PETSC_DLLEXPORT PetscFListView(PetscFList list,PetscViewer viewer)
448 {
449   PetscErrorCode ierr;
450   PetscTruth     iascii;
451 
452   PetscFunctionBegin;
453   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;
454   PetscValidPointer(list,1);
455   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_COOKIE,2);
456 
457   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr);
458   if (!iascii) SETERRQ(PETSC_ERR_SUP,"Only ASCII viewer supported");
459 
460   while (list) {
461     if (list->path) {
462       ierr = PetscViewerASCIIPrintf(viewer," %s %s %s\n",list->path,list->name,list->rname);CHKERRQ(ierr);
463     } else {
464       ierr = PetscViewerASCIIPrintf(viewer," %s %s\n",list->name,list->rname);CHKERRQ(ierr);
465     }
466     list = list->next;
467   }
468   ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
469   PetscFunctionReturn(0);
470 }
471 
472 #undef __FUNCT__
473 #define __FUNCT__ "PetscFListGet"
474 /*@
475    PetscFListGet - Gets an array the contains the entries in PetscFList, this is used
476          by help etc.
477 
478    Collective over MPI_Comm
479 
480    Input Parameter:
481 .  list   - list of types
482 
483    Output Parameter:
484 +  array - array of names
485 -  n - length of array
486 
487    Notes:
488        This allocates the array so that must be freed. BUT the individual entries are
489     not copied so should not be freed.
490 
491    Level: developer
492 
493 .seealso: PetscFListAddDynamic(), PetscFList
494 @*/
495 PetscErrorCode PETSC_DLLEXPORT PetscFListGet(PetscFList list,char ***array,int *n)
496 {
497   PetscErrorCode ierr;
498   PetscInt       count = 0;
499   PetscFList     klist = list;
500 
501   PetscFunctionBegin;
502   while (list) {
503     list = list->next;
504     count++;
505   }
506   ierr  = PetscMalloc((count+1)*sizeof(char *),array);CHKERRQ(ierr);
507   count = 0;
508   while (klist) {
509     (*array)[count] = klist->name;
510     klist = klist->next;
511     count++;
512   }
513   (*array)[count] = 0;
514   *n = count+1;
515 
516   PetscFunctionReturn(0);
517 }
518 
519 
520 #undef __FUNCT__
521 #define __FUNCT__ "PetscFListPrintTypes"
522 /*@C
523    PetscFListPrintTypes - Prints the methods available.
524 
525    Collective over MPI_Comm
526 
527    Input Parameters:
528 +  comm   - the communicator (usually MPI_COMM_WORLD)
529 .  fd     - file to print to, usually stdout
530 .  prefix - prefix to prepend to name (optional)
531 .  name   - option string (for example, "-ksp_type")
532 .  text - short description of the object (for example, "Krylov solvers")
533 .  man - name of manual page that discusses the object (for example, "KSPCreate")
534 -  list   - list of types
535 
536    Level: developer
537 
538 .seealso: PetscFListAddDynamic(), PetscFList
539 @*/
540 PetscErrorCode PETSC_DLLEXPORT PetscFListPrintTypes(PetscFList list,MPI_Comm comm,FILE *fd,const char prefix[],const char name[],const char text[],const char man[])
541 {
542   PetscErrorCode ierr;
543   PetscInt       count = 0;
544   char           p[64];
545 
546   PetscFunctionBegin;
547   if (!fd) fd = PETSC_STDOUT;
548 
549   ierr = PetscStrcpy(p,"-");CHKERRQ(ierr);
550   if (prefix) {ierr = PetscStrcat(p,prefix);CHKERRQ(ierr);}
551   ierr = PetscFPrintf(comm,fd,"  %s%s %s:(one of)",p,name+1,text);CHKERRQ(ierr);
552 
553   while (list) {
554     ierr = PetscFPrintf(comm,fd," %s",list->name);CHKERRQ(ierr);
555     list = list->next;
556     count++;
557     if (count == 8) {ierr = PetscFPrintf(comm,fd,"\n     ");CHKERRQ(ierr);}
558   }
559   ierr = PetscFPrintf(comm,fd," (%s)\n",man);CHKERRQ(ierr);
560   PetscFunctionReturn(0);
561 }
562 
563 #undef __FUNCT__
564 #define __FUNCT__ "PetscFListDuplicate"
565 /*@
566     PetscFListDuplicate - Creates a new list from a given object list.
567 
568     Input Parameters:
569 .   fl   - pointer to list
570 
571     Output Parameters:
572 .   nl - the new list (should point to 0 to start, otherwise appends)
573 
574     Level: developer
575 
576 .seealso: PetscFList, PetscFListAdd(), PetscFlistDestroy()
577 
578 @*/
579 PetscErrorCode PETSC_DLLEXPORT PetscFListDuplicate(PetscFList fl,PetscFList *nl)
580 {
581   PetscErrorCode ierr;
582   char           path[PETSC_MAX_PATH_LEN];
583 
584   PetscFunctionBegin;
585   while (fl) {
586     /* this is silly, rebuild the complete pathname */
587     if (fl->path) {
588       ierr = PetscStrcpy(path,fl->path);CHKERRQ(ierr);
589       ierr = PetscStrcat(path,":");CHKERRQ(ierr);
590       ierr = PetscStrcat(path,fl->name);CHKERRQ(ierr);
591     } else {
592       ierr = PetscStrcpy(path,fl->name);CHKERRQ(ierr);
593     }
594     ierr = PetscFListAdd(nl,path,fl->rname,fl->routine);CHKERRQ(ierr);
595     fl   = fl->next;
596   }
597   PetscFunctionReturn(0);
598 }
599 
600 
601 #undef __FUNCT__
602 #define __FUNCT__ "PetscFListConcat"
603 /*
604     PetscFListConcat - joins name of a libary, and the path where it is located
605     into a single string.
606 
607     Input Parameters:
608 .   path   - path to the library name.
609 .   name   - name of the library
610 
611     Output Parameters:
612 .   fullname - the name that is the union of the path and the library name,
613                delimited by a semicolon, i.e., path:name
614 
615     Notes:
616     If the path is NULL, assumes that the name, specified also includes
617     the path as path:name
618 
619 */
620 PetscErrorCode PETSC_DLLEXPORT PetscFListConcat(const char path[],const char name[],char fullname[])
621 {
622   PetscErrorCode ierr;
623   PetscFunctionBegin;
624   if (path) {
625     ierr = PetscStrcpy(fullname,path);CHKERRQ(ierr);
626     ierr = PetscStrcat(fullname,":");CHKERRQ(ierr);
627     ierr = PetscStrcat(fullname,name);CHKERRQ(ierr);
628   } else {
629     ierr = PetscStrcpy(fullname,name);CHKERRQ(ierr);
630   }
631   PetscFunctionReturn(0);
632 }
633