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