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