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