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