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