xref: /petsc/src/sys/fileio/mprint.c (revision efa12513287cff49a2b9648ae83199dcbfaad71a)
1 /*
2       Utilites routines to add simple ASCII IO capability.
3 */
4 #include <../src/sys/fileio/mprint.h>
5 #include <errno.h>
6 /*
7    If petsc_history is on, then all Petsc*Printf() results are saved
8    if the appropriate (usually .petschistory) file.
9 */
10 PETSC_INTERN FILE *petsc_history;
11 /*
12      Allows one to overwrite where standard out is sent. For example
13      PETSC_STDOUT = fopen("/dev/ttyXX","w") will cause all standard out
14      writes to go to terminal XX; assuming you have write permission there
15 */
16 FILE *PETSC_STDOUT = NULL;
17 /*
18      Allows one to overwrite where standard error is sent. For example
19      PETSC_STDERR = fopen("/dev/ttyXX","w") will cause all standard error
20      writes to go to terminal XX; assuming you have write permission there
21 */
22 FILE *PETSC_STDERR = NULL;
23 
24 /*@C
25      PetscFormatConvertGetSize - Gets the length of a string needed to hold format converted with PetscFormatConvert()
26 
27    Input Parameter:
28 .   format - the PETSc format string
29 
30    Output Parameter:
31 .   size - the needed length of the new format
32 
33  Level: developer
34 
35 .seealso: PetscFormatConvert(), PetscVSNPrintf(), PetscVFPrintf()
36 
37 @*/
38 PetscErrorCode PetscFormatConvertGetSize(const char *format,size_t *size)
39 {
40   PetscInt i = 0;
41 
42   PetscFunctionBegin;
43   *size = 0;
44   while (format[i]) {
45     if (format[i] == '%' && format[i+1] == '%') {
46       i++; i++; *size += 2;
47     } else if (format[i] == '%') {
48       /* Find the letter */
49       for (; format[i] && format[i] <= '9'; i++,(*size += 1));
50       switch (format[i]) {
51       case 'D':
52 #if defined(PETSC_USE_64BIT_INDICES)
53         *size += 2;
54 #endif
55         break;
56       case 'g':
57         *size += 4;
58         break;
59       default:
60         break;
61       }
62       *size += 1;
63       i++;
64     } else {
65       i++;
66       *size += 1;
67     }
68   }
69   *size += 1; /* space for NULL character */
70   PetscFunctionReturn(0);
71 }
72 
73 /*@C
74      PetscFormatConvert - Takes a PETSc format string and converts the %D to %d for 32 bit PETSc indices and %lld for 64 bit PETSc indices. Also
75                         converts %g to [|%g|] so that PetscVSNPrintf() can easily insure all %g formatted numbers have a decimal point when printed.
76 
77    Input Parameters:
78 +   format - the PETSc format string
79 .   newformat - the location to put the new format
80 -   size - the length of newformat, you can use PetscFormatConvertGetSize() to compute the needed size
81 
82     Note: this exists so we can have the same code when PetscInt is either int or long long int
83 
84  Level: developer
85 
86 .seealso: PetscFormatConvertGetSize(), PetscVSNPrintf(), PetscVFPrintf()
87 
88 @*/
89 PetscErrorCode PetscFormatConvert(const char *format,char *newformat)
90 {
91   PetscInt i = 0, j = 0;
92 
93   PetscFunctionBegin;
94   while (format[i]) {
95     if (format[i] == '%' && format[i+1] == '%') {
96       newformat[j++] = format[i++];
97       newformat[j++] = format[i++];
98     } else if (format[i] == '%') {
99       if (format[i+1] == 'g') {
100         newformat[j++] = '[';
101         newformat[j++] = '|';
102       }
103       /* Find the letter */
104       for (; format[i] && format[i] <= '9'; i++) newformat[j++] = format[i];
105       switch (format[i]) {
106       case 'D':
107 #if !defined(PETSC_USE_64BIT_INDICES)
108         newformat[j++] = 'd';
109 #else
110         newformat[j++] = 'l';
111         newformat[j++] = 'l';
112         newformat[j++] = 'd';
113 #endif
114         break;
115       case 'g':
116         newformat[j++] = format[i];
117         if (format[i-1] == '%') {
118           newformat[j++] = '|';
119           newformat[j++] = ']';
120         }
121         break;
122       case 'G':
123         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"%%G format is no longer supported, use %%g and cast the argument to double");
124       case 'F':
125         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"%%F format is no longer supported, use %%f and cast the argument to double");
126       default:
127         newformat[j++] = format[i];
128         break;
129       }
130       i++;
131     } else newformat[j++] = format[i++];
132   }
133   newformat[j] = 0;
134   PetscFunctionReturn(0);
135 }
136 
137 #define PETSCDEFAULTBUFFERSIZE 8*1024
138 
139 /*@C
140      PetscVSNPrintf - The PETSc version of vsnprintf(). Converts a PETSc format string into a standard C format string and then puts all the
141        function arguments into a string using the format statement.
142 
143    Input Parameters:
144 +   str - location to put result
145 .   len - the amount of space in str
146 +   format - the PETSc format string
147 -   fullLength - the amount of space in str actually used.
148 
149     Developer Notes:
150     this function may be called from an error handler, if an error occurs when it is called by the error handler than likely
151       a recursion will occur and possible crash.
152 
153  Level: developer
154 
155 .seealso: PetscVSNPrintf(), PetscErrorPrintf(), PetscVPrintf()
156 
157 @*/
158 PetscErrorCode PetscVSNPrintf(char *str,size_t len,const char *format,size_t *fullLength,va_list Argp)
159 {
160   char           *newformat = NULL;
161   char           formatbuf[PETSCDEFAULTBUFFERSIZE];
162   size_t         newLength;
163   PetscErrorCode ierr;
164   int            flen;
165 
166   PetscFunctionBegin;
167   ierr = PetscFormatConvertGetSize(format,&newLength);CHKERRQ(ierr);
168   if (newLength < PETSCDEFAULTBUFFERSIZE) {
169     newformat = formatbuf;
170     newLength = PETSCDEFAULTBUFFERSIZE-1;
171   } else {
172     ierr      = PetscMalloc1(newLength, &newformat);CHKERRQ(ierr);
173   }
174   ierr = PetscFormatConvert(format,newformat);CHKERRQ(ierr);
175 #if defined(PETSC_HAVE_VSNPRINTF)
176   flen = vsnprintf(str,len,newformat,Argp);
177 #else
178 #error "vsnprintf not found"
179 #endif
180   if (newLength > PETSCDEFAULTBUFFERSIZE-1) {
181     ierr = PetscFree(newformat);CHKERRQ(ierr);
182   }
183   {
184     PetscBool foundedot;
185     size_t cnt = 0,ncnt = 0,leng;
186     ierr = PetscStrlen(str,&leng);CHKERRQ(ierr);
187     if (leng > 4) {
188       for (cnt=0; cnt<leng-4; cnt++) {
189         if (str[cnt] == '[' && str[cnt+1] == '|'){
190           flen -= 4;
191           cnt++; cnt++;
192           foundedot = PETSC_FALSE;
193           for (; cnt<leng-1; cnt++) {
194             if (str[cnt] == '|' && str[cnt+1] == ']'){
195               cnt++;
196               if (!foundedot) str[ncnt++] = '.';
197               ncnt--;
198               break;
199             } else {
200               if (str[cnt] == 'e' || str[cnt] == '.') foundedot = PETSC_TRUE;
201               str[ncnt++] = str[cnt];
202             }
203           }
204         } else {
205           str[ncnt] = str[cnt];
206         }
207         ncnt++;
208       }
209       while (cnt < leng) {
210         str[ncnt] = str[cnt]; ncnt++; cnt++;
211       }
212       str[ncnt] = 0;
213     }
214   }
215 #if defined(PETSC_HAVE_WINDOWS_H) && !defined(PETSC_HAVE__SET_OUTPUT_FORMAT)
216   /* older Windows OS always produces e-+0np for floating point output; remove the extra 0 */
217   {
218     size_t cnt = 0,ncnt = 0,leng;
219     ierr = PetscStrlen(str,&leng);CHKERRQ(ierr);
220     if (leng > 5) {
221       for (cnt=0; cnt<leng-4; cnt++) {
222         if (str[cnt] == 'e' && (str[cnt+1] == '-' || str[cnt+1] == '+') && str[cnt+2] == '0'  && str[cnt+3] >= '0' && str[cnt+3] <= '9' && str[cnt+4] >= '0' && str[cnt+4] <= '9') {
223           str[ncnt] = str[cnt]; ncnt++; cnt++;
224           str[ncnt] = str[cnt]; ncnt++; cnt++; cnt++;
225           str[ncnt] = str[cnt];
226         } else {
227           str[ncnt] = str[cnt];
228         }
229         ncnt++;
230       }
231       while (cnt < leng) {
232         str[ncnt] = str[cnt]; ncnt++; cnt++;
233       }
234       str[ncnt] = 0;
235     }
236   }
237 #endif
238   if (fullLength) *fullLength = 1 + (size_t) flen;
239   PetscFunctionReturn(0);
240 }
241 
242 /*@C
243      PetscVFPrintf -  All PETSc standard out and error messages are sent through this function; so, in theory, this can
244         can be replaced with something that does not simply write to a file.
245 
246       To use, write your own function for example,
247 $PetscErrorCode mypetscvfprintf(FILE *fd,const char format[],va_list Argp)
248 ${
249 $  PetscErrorCode ierr;
250 $
251 $  PetscFunctionBegin;
252 $   if (fd != stdout && fd != stderr) {  handle regular files
253 $      ierr = PetscVFPrintfDefault(fd,format,Argp);CHKERR(ierr);
254 $  } else {
255 $     char   buff[BIG];
256 $     size_t length;
257 $     ierr = PetscVSNPrintf(buff,BIG,format,&length,Argp);CHKERRQ(ierr);
258 $     now send buff to whatever stream or whatever you want
259 $ }
260 $ PetscFunctionReturn(0);
261 $}
262 then before the call to PetscInitialize() do the assignment
263 $    PetscVFPrintf = mypetscvfprintf;
264 
265       Notes:
266     For error messages this may be called by any process, for regular standard out it is
267           called only by process 0 of a given communicator
268 
269       Developer Notes:
270     this could be called by an error handler, if that happens then a recursion of the error handler may occur
271                        and a crash
272 
273   Level:  developer
274 
275 .seealso: PetscVSNPrintf(), PetscErrorPrintf()
276 
277 @*/
278 PetscErrorCode PetscVFPrintfDefault(FILE *fd,const char *format,va_list Argp)
279 {
280   char           str[PETSCDEFAULTBUFFERSIZE];
281   char           *buff = str;
282   size_t         fullLength;
283   PetscErrorCode ierr;
284 #if defined(PETSC_HAVE_VA_COPY)
285   va_list        Argpcopy;
286 #endif
287 
288   PetscFunctionBegin;
289 #if defined(PETSC_HAVE_VA_COPY)
290   va_copy(Argpcopy,Argp);
291 #endif
292   ierr = PetscVSNPrintf(str,sizeof(str),format,&fullLength,Argp);CHKERRQ(ierr);
293   if (fullLength > sizeof(str)) {
294     ierr = PetscMalloc1(fullLength,&buff);CHKERRQ(ierr);
295 #if defined(PETSC_HAVE_VA_COPY)
296     ierr = PetscVSNPrintf(buff,fullLength,format,NULL,Argpcopy);CHKERRQ(ierr);
297 #else
298     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"C89 does not support va_copy() hence cannot print long strings with PETSc printing routines");
299 #endif
300   }
301   fprintf(fd,"%s",buff);CHKERRQ(ierr);
302   fflush(fd);
303   if (buff != str) {
304     ierr = PetscFree(buff);CHKERRQ(ierr);
305   }
306   PetscFunctionReturn(0);
307 }
308 
309 /*@C
310     PetscSNPrintf - Prints to a string of given length
311 
312     Not Collective
313 
314     Input Parameters:
315 +   str - the string to print to
316 .   len - the length of str
317 .   format - the usual printf() format string
318 -   any arguments
319 
320    Level: intermediate
321 
322 .seealso: PetscSynchronizedFlush(), PetscSynchronizedFPrintf(), PetscFPrintf(), PetscVSNPrintf(),
323           PetscPrintf(), PetscViewerASCIIPrintf(), PetscViewerASCIISynchronizedPrintf(), PetscVFPrintf()
324 @*/
325 PetscErrorCode PetscSNPrintf(char *str,size_t len,const char format[],...)
326 {
327   PetscErrorCode ierr;
328   size_t         fullLength;
329   va_list        Argp;
330 
331   PetscFunctionBegin;
332   va_start(Argp,format);
333   ierr = PetscVSNPrintf(str,len,format,&fullLength,Argp);CHKERRQ(ierr);
334   PetscFunctionReturn(0);
335 }
336 
337 /*@C
338     PetscSNPrintfCount - Prints to a string of given length, returns count
339 
340     Not Collective
341 
342     Input Parameters:
343 +   str - the string to print to
344 .   len - the length of str
345 .   format - the usual printf() format string
346 -   any arguments
347 
348     Output Parameter:
349 .   countused - number of characters used
350 
351    Level: intermediate
352 
353 .seealso: PetscSynchronizedFlush(), PetscSynchronizedFPrintf(), PetscFPrintf(), PetscVSNPrintf(),
354           PetscPrintf(), PetscViewerASCIIPrintf(), PetscViewerASCIISynchronizedPrintf(), PetscSNPrintf(), PetscVFPrintf()
355 @*/
356 PetscErrorCode PetscSNPrintfCount(char *str,size_t len,const char format[],size_t *countused,...)
357 {
358   PetscErrorCode ierr;
359   va_list        Argp;
360 
361   PetscFunctionBegin;
362   va_start(Argp,countused);
363   ierr = PetscVSNPrintf(str,len,format,countused,Argp);CHKERRQ(ierr);
364   PetscFunctionReturn(0);
365 }
366 
367 /* ----------------------------------------------------------------------- */
368 
369 PrintfQueue petsc_printfqueue       = NULL,petsc_printfqueuebase = NULL;
370 int         petsc_printfqueuelength = 0;
371 
372 /*@C
373     PetscSynchronizedPrintf - Prints synchronized output from several processors.
374     Output of the first processor is followed by that of the second, etc.
375 
376     Not Collective
377 
378     Input Parameters:
379 +   comm - the communicator
380 -   format - the usual printf() format string
381 
382    Level: intermediate
383 
384     Notes:
385     REQUIRES a call to PetscSynchronizedFlush() by all the processes after the completion of the calls to PetscSynchronizedPrintf() for the information
386     from all the processors to be printed.
387 
388     Fortran Note:
389     The call sequence is PetscSynchronizedPrintf(MPI_Comm, character(*), PetscErrorCode ierr) from Fortran.
390     That is, you can only pass a single character string from Fortran.
391 
392 .seealso: PetscSynchronizedFlush(), PetscSynchronizedFPrintf(), PetscFPrintf(),
393           PetscPrintf(), PetscViewerASCIIPrintf(), PetscViewerASCIISynchronizedPrintf()
394 @*/
395 PetscErrorCode PetscSynchronizedPrintf(MPI_Comm comm,const char format[],...)
396 {
397   PetscErrorCode ierr;
398   PetscMPIInt    rank;
399 
400   PetscFunctionBegin;
401   if (comm == MPI_COMM_NULL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
402   ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
403 
404   /* First processor prints immediately to stdout */
405   if (!rank) {
406     va_list Argp;
407     va_start(Argp,format);
408     ierr = (*PetscVFPrintf)(PETSC_STDOUT,format,Argp);CHKERRQ(ierr);
409     if (petsc_history) {
410       va_start(Argp,format);
411       ierr = (*PetscVFPrintf)(petsc_history,format,Argp);CHKERRQ(ierr);
412     }
413     va_end(Argp);
414   } else { /* other processors add to local queue */
415     va_list     Argp;
416     PrintfQueue next;
417     size_t      fullLength = PETSCDEFAULTBUFFERSIZE;
418 
419     ierr = PetscNew(&next);CHKERRQ(ierr);
420     if (petsc_printfqueue) {
421       petsc_printfqueue->next = next;
422       petsc_printfqueue       = next;
423       petsc_printfqueue->next = NULL;
424     } else petsc_printfqueuebase = petsc_printfqueue = next;
425     petsc_printfqueuelength++;
426     next->size   = -1;
427     next->string = NULL;
428     while ((PetscInt)fullLength >= next->size) {
429       next->size = fullLength+1;
430       ierr = PetscFree(next->string);CHKERRQ(ierr);
431       ierr = PetscMalloc1(next->size, &next->string);CHKERRQ(ierr);
432       va_start(Argp,format);
433       ierr = PetscArrayzero(next->string,next->size);CHKERRQ(ierr);
434       ierr = PetscVSNPrintf(next->string,next->size,format, &fullLength,Argp);CHKERRQ(ierr);
435       va_end(Argp);
436     }
437   }
438   PetscFunctionReturn(0);
439 }
440 
441 /*@C
442     PetscSynchronizedFPrintf - Prints synchronized output to the specified file from
443     several processors.  Output of the first processor is followed by that of the
444     second, etc.
445 
446     Not Collective
447 
448     Input Parameters:
449 +   comm - the communicator
450 .   fd - the file pointer
451 -   format - the usual printf() format string
452 
453     Level: intermediate
454 
455     Notes:
456     REQUIRES a intervening call to PetscSynchronizedFlush() for the information
457     from all the processors to be printed.
458 
459 .seealso: PetscSynchronizedPrintf(), PetscSynchronizedFlush(), PetscFPrintf(),
460           PetscFOpen(), PetscViewerASCIISynchronizedPrintf(), PetscViewerASCIIPrintf()
461 
462 @*/
463 PetscErrorCode PetscSynchronizedFPrintf(MPI_Comm comm,FILE *fp,const char format[],...)
464 {
465   PetscErrorCode ierr;
466   PetscMPIInt    rank;
467 
468   PetscFunctionBegin;
469   if (comm == MPI_COMM_NULL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
470   ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
471 
472   /* First processor prints immediately to fp */
473   if (!rank) {
474     va_list Argp;
475     va_start(Argp,format);
476     ierr = (*PetscVFPrintf)(fp,format,Argp);CHKERRQ(ierr);
477     if (petsc_history && (fp !=petsc_history)) {
478       va_start(Argp,format);
479       ierr = (*PetscVFPrintf)(petsc_history,format,Argp);CHKERRQ(ierr);
480     }
481     va_end(Argp);
482   } else { /* other processors add to local queue */
483     va_list     Argp;
484     PrintfQueue next;
485     size_t      fullLength = PETSCDEFAULTBUFFERSIZE;
486 
487     ierr = PetscNew(&next);CHKERRQ(ierr);
488     if (petsc_printfqueue) {
489       petsc_printfqueue->next = next;
490       petsc_printfqueue       = next;
491       petsc_printfqueue->next = NULL;
492     } else petsc_printfqueuebase = petsc_printfqueue = next;
493     petsc_printfqueuelength++;
494     next->size   = -1;
495     next->string = NULL;
496     while ((PetscInt)fullLength >= next->size) {
497       next->size = fullLength+1;
498       ierr = PetscFree(next->string);CHKERRQ(ierr);
499       ierr = PetscMalloc1(next->size, &next->string);CHKERRQ(ierr);
500       va_start(Argp,format);
501       ierr = PetscArrayzero(next->string,next->size);CHKERRQ(ierr);
502       ierr = PetscVSNPrintf(next->string,next->size,format,&fullLength,Argp);CHKERRQ(ierr);
503       va_end(Argp);
504     }
505   }
506   PetscFunctionReturn(0);
507 }
508 
509 /*@C
510     PetscSynchronizedFlush - Flushes to the screen output from all processors
511     involved in previous PetscSynchronizedPrintf()/PetscSynchronizedFPrintf() calls.
512 
513     Collective
514 
515     Input Parameters:
516 +   comm - the communicator
517 -   fd - the file pointer (valid on process 0 of the communicator)
518 
519     Level: intermediate
520 
521     Notes:
522     If PetscSynchronizedPrintf() and/or PetscSynchronizedFPrintf() are called with
523     different MPI communicators there must be an intervening call to PetscSynchronizedFlush() between the calls with different MPI communicators.
524 
525     From Fortran pass PETSC_STDOUT if the flush is for standard out; otherwise pass a value obtained from PetscFOpen()
526 
527 .seealso: PetscSynchronizedPrintf(), PetscFPrintf(), PetscPrintf(), PetscViewerASCIIPrintf(),
528           PetscViewerASCIISynchronizedPrintf()
529 @*/
530 PetscErrorCode PetscSynchronizedFlush(MPI_Comm comm,FILE *fd)
531 {
532   PetscErrorCode ierr;
533   PetscMPIInt    rank,size,tag,i,j,n = 0,dummy = 0;
534   char          *message;
535   MPI_Status     status;
536 
537   PetscFunctionBegin;
538   ierr = PetscCommDuplicate(comm,&comm,&tag);CHKERRQ(ierr);
539   ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
540   ierr = MPI_Comm_size(comm,&size);CHKERRMPI(ierr);
541 
542   /* First processor waits for messages from all other processors */
543   if (!rank) {
544     if (!fd) fd = PETSC_STDOUT;
545     for (i=1; i<size; i++) {
546       /* to prevent a flood of messages to process zero, request each message separately */
547       ierr = MPI_Send(&dummy,1,MPI_INT,i,tag,comm);CHKERRMPI(ierr);
548       ierr = MPI_Recv(&n,1,MPI_INT,i,tag,comm,&status);CHKERRMPI(ierr);
549       for (j=0; j<n; j++) {
550         PetscMPIInt size = 0;
551 
552         ierr = MPI_Recv(&size,1,MPI_INT,i,tag,comm,&status);CHKERRMPI(ierr);
553         ierr = PetscMalloc1(size, &message);CHKERRQ(ierr);
554         ierr = MPI_Recv(message,size,MPI_CHAR,i,tag,comm,&status);CHKERRMPI(ierr);
555         ierr = PetscFPrintf(comm,fd,"%s",message);CHKERRQ(ierr);
556         ierr = PetscFree(message);CHKERRQ(ierr);
557       }
558     }
559   } else { /* other processors send queue to processor 0 */
560     PrintfQueue next = petsc_printfqueuebase,previous;
561 
562     ierr = MPI_Recv(&dummy,1,MPI_INT,0,tag,comm,&status);CHKERRMPI(ierr);
563     ierr = MPI_Send(&petsc_printfqueuelength,1,MPI_INT,0,tag,comm);CHKERRMPI(ierr);
564     for (i=0; i<petsc_printfqueuelength; i++) {
565       ierr     = MPI_Send(&next->size,1,MPI_INT,0,tag,comm);CHKERRQ(ierr);
566       ierr     = MPI_Send(next->string,next->size,MPI_CHAR,0,tag,comm);CHKERRQ(ierr);
567       previous = next;
568       next     = next->next;
569       ierr     = PetscFree(previous->string);CHKERRQ(ierr);
570       ierr     = PetscFree(previous);CHKERRQ(ierr);
571     }
572     petsc_printfqueue       = NULL;
573     petsc_printfqueuelength = 0;
574   }
575   ierr = PetscCommDestroy(&comm);CHKERRQ(ierr);
576   PetscFunctionReturn(0);
577 }
578 
579 /* ---------------------------------------------------------------------------------------*/
580 
581 /*@C
582     PetscFPrintf - Prints to a file, only from the first
583     processor in the communicator.
584 
585     Not Collective
586 
587     Input Parameters:
588 +   comm - the communicator
589 .   fd - the file pointer
590 -   format - the usual printf() format string
591 
592     Level: intermediate
593 
594     Fortran Note:
595     This routine is not supported in Fortran.
596 
597 
598 .seealso: PetscPrintf(), PetscSynchronizedPrintf(), PetscViewerASCIIPrintf(),
599           PetscViewerASCIISynchronizedPrintf(), PetscSynchronizedFlush()
600 @*/
601 PetscErrorCode PetscFPrintf(MPI_Comm comm,FILE* fd,const char format[],...)
602 {
603   PetscErrorCode ierr;
604   PetscMPIInt    rank;
605 
606   PetscFunctionBegin;
607   if (comm == MPI_COMM_NULL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
608   ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
609   if (!rank) {
610     va_list Argp;
611     va_start(Argp,format);
612     ierr = (*PetscVFPrintf)(fd,format,Argp);CHKERRQ(ierr);
613     if (petsc_history && (fd !=petsc_history)) {
614       va_start(Argp,format);
615       ierr = (*PetscVFPrintf)(petsc_history,format,Argp);CHKERRQ(ierr);
616     }
617     va_end(Argp);
618   }
619   PetscFunctionReturn(0);
620 }
621 
622 /*@C
623     PetscPrintf - Prints to standard out, only from the first
624     processor in the communicator. Calls from other processes are ignored.
625 
626     Not Collective
627 
628     Input Parameters:
629 +   comm - the communicator
630 -   format - the usual printf() format string
631 
632     Level: intermediate
633 
634     Notes:
635     PetscPrintf() supports some format specifiers that are unique to PETSc.
636     See the manual page for PetscFormatConvert() for details.
637 
638     Fortran Note:
639     The call sequence is PetscPrintf(MPI_Comm, character(*), PetscErrorCode ierr) from Fortran.
640     That is, you can only pass a single character string from Fortran.
641 
642 
643 .seealso: PetscFPrintf(), PetscSynchronizedPrintf(), PetscFormatConvert()
644 @*/
645 PetscErrorCode PetscPrintf(MPI_Comm comm,const char format[],...)
646 {
647   PetscErrorCode ierr;
648   PetscMPIInt    rank;
649 
650   PetscFunctionBegin;
651   if (comm == MPI_COMM_NULL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
652   ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
653   if (!rank) {
654     va_list Argp;
655     va_start(Argp,format);
656     ierr = (*PetscVFPrintf)(PETSC_STDOUT,format,Argp);CHKERRQ(ierr);
657     if (petsc_history) {
658       va_start(Argp,format);
659       ierr = (*PetscVFPrintf)(petsc_history,format,Argp);CHKERRQ(ierr);
660     }
661     va_end(Argp);
662   }
663   PetscFunctionReturn(0);
664 }
665 
666 PetscErrorCode PetscHelpPrintfDefault(MPI_Comm comm,const char format[],...)
667 {
668   PetscErrorCode ierr;
669   PetscMPIInt    rank;
670 
671   PetscFunctionBegin;
672   if (comm == MPI_COMM_NULL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
673   ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
674   if (!rank) {
675     va_list Argp;
676     va_start(Argp,format);
677     ierr = (*PetscVFPrintf)(PETSC_STDOUT,format,Argp);CHKERRQ(ierr);
678     if (petsc_history) {
679       va_start(Argp,format);
680       ierr = (*PetscVFPrintf)(petsc_history,format,Argp);CHKERRQ(ierr);
681     }
682     va_end(Argp);
683   }
684   PetscFunctionReturn(0);
685 }
686 
687 /* ---------------------------------------------------------------------------------------*/
688 
689 
690 /*@C
691     PetscSynchronizedFGets - Several processors all get the same line from a file.
692 
693     Collective
694 
695     Input Parameters:
696 +   comm - the communicator
697 .   fd - the file pointer
698 -   len - the length of the output buffer
699 
700     Output Parameter:
701 .   string - the line read from the file, at end of file string[0] == 0
702 
703     Level: intermediate
704 
705 .seealso: PetscSynchronizedPrintf(), PetscSynchronizedFlush(),
706           PetscFOpen(), PetscViewerASCIISynchronizedPrintf(), PetscViewerASCIIPrintf()
707 
708 @*/
709 PetscErrorCode PetscSynchronizedFGets(MPI_Comm comm,FILE *fp,size_t len,char string[])
710 {
711   PetscErrorCode ierr;
712   PetscMPIInt    rank;
713 
714   PetscFunctionBegin;
715   ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
716 
717   if (!rank) {
718     char *ptr = fgets(string, len, fp);
719 
720     if (!ptr) {
721       string[0] = 0;
722       if (!feof(fp)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from file: %d", errno);
723     }
724   }
725   ierr = MPI_Bcast(string,len,MPI_BYTE,0,comm);CHKERRMPI(ierr);
726   PetscFunctionReturn(0);
727 }
728 
729 #if defined(PETSC_HAVE_CLOSURE)
730 int (^SwiftClosure)(const char*) = 0;
731 
732 PetscErrorCode PetscVFPrintfToString(FILE *fd,const char format[],va_list Argp)
733 {
734   PetscErrorCode ierr;
735 
736   PetscFunctionBegin;
737   if (fd != stdout && fd != stderr) { /* handle regular files */
738     ierr = PetscVFPrintfDefault(fd,format,Argp);CHKERRQ(ierr);
739   } else {
740     size_t length;
741     char   buff[PETSCDEFAULTBUFFERSIZE];
742 
743     ierr = PetscVSNPrintf(buff,sizeof(buff),format,&length,Argp);CHKERRQ(ierr);
744     ierr = SwiftClosure(buff);CHKERRQ(ierr);
745   }
746   PetscFunctionReturn(0);
747 }
748 
749 /*
750    Provide a Swift function that processes all the PETSc calls to PetscVFPrintf()
751 */
752 PetscErrorCode PetscVFPrintfSetClosure(int (^closure)(const char*))
753 {
754   PetscVFPrintf = PetscVFPrintfToString;
755   SwiftClosure  = closure;
756   return 0;
757 }
758 #endif
759 
760 /*@C
761      PetscFormatStrip - Takes a PETSc format string and removes all numerical modifiers to % operations
762 
763    Input Parameters:
764 .   format - the PETSc format string
765 
766  Level: developer
767 
768 @*/
769 PetscErrorCode PetscFormatStrip(char *format)
770 {
771   size_t loc1 = 0, loc2 = 0;
772 
773   PetscFunctionBegin;
774   while (format[loc2]) {
775     if (format[loc2] == '%') {
776       format[loc1++] = format[loc2++];
777       while (format[loc2] && ((format[loc2] >= '0' && format[loc2] <= '9') || format[loc2] == '.')) loc2++;
778     }
779     format[loc1++] = format[loc2++];
780   }
781   PetscFunctionReturn(0);
782 }
783 
784 PetscErrorCode PetscFormatRealArray(char buf[],size_t len,const char *fmt,PetscInt n,const PetscReal x[])
785 {
786   PetscErrorCode ierr;
787   PetscInt       i;
788   size_t         left,count;
789   char           *p;
790 
791   PetscFunctionBegin;
792   for (i=0,p=buf,left=len; i<n; i++) {
793     ierr = PetscSNPrintfCount(p,left,fmt,&count,(double)x[i]);CHKERRQ(ierr);
794     if (count >= left) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Insufficient space in buffer");
795     left -= count;
796     p    += count-1;
797     *p++  = ' ';
798   }
799   p[i ? 0 : -1] = 0;
800   PetscFunctionReturn(0);
801 }
802