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