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