Actual source code: mprint.c

  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;

 24: /*@C
 25:      PetscFormatConvertGetSize - Gets the length of a string needed to hold format converted with `PetscFormatConvert()`

 27:    Deprecated

 29:    Input Parameter:
 30: .   format - the PETSc format string

 32:    Output Parameter:
 33: .   size - the needed length of the new format

 35:  Level: developer

 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;

 46:   while (format[i]) {
 47:     if (format[i] == '%') {
 48:       if (format[i + 1] == '%') {
 49:         i += 2;
 50:         sz += 2;
 51:         continue;
 52:       }
 53:       /* Find the letter */
 54:       while (format[i] && (format[i] <= '9')) {
 55:         ++i;
 56:         ++sz;
 57:       }
 58:       switch (format[i]) {
 59: #if PetscDefined(USE_64BIT_INDICES)
 60:       case 'D':
 61:         sz += 2;
 62:         break;
 63: #endif
 64:       case 'g':
 65:         sz += 4;
 66:       default:
 67:         break;
 68:       }
 69:     }
 70:     ++i;
 71:     ++sz;
 72:   }
 73:   *size = sz + 1; /* space for NULL character */
 74:   return 0;
 75: }

 77: /*@C
 78:      PetscFormatConvert - Takes a PETSc format string and converts the %D to %d for 32 bit PETSc indices and %lld for 64 bit PETSc indices. Also
 79:                         converts %g to [|%g|] so that PetscVSNPrintf() can easily insure all %g formatted numbers have a decimal point when printed.

 81:    Deprecated

 83:    Input Parameters:
 84: +   format - the PETSc format string
 85: .   newformat - the location to put the new format
 86: -   size - the length of newformat, you can use `PetscFormatConvertGetSize()` to compute the needed size

 88:     Note: this exists so we can have the same code when `PetscInt` is either int or long long int

 90:  Level: developer

 92: .seealso: `PetscFormatConvertGetSize()`, `PetscVSNPrintf()`, `PetscVFPrintf()`
 93: @*/
 94: PetscErrorCode PetscFormatConvert(const char *format, char *newformat)
 95: {
 96:   PetscInt i = 0, j = 0;

 98:   while (format[i]) {
 99:     if (format[i] == '%' && format[i + 1] == '%') {
100:       newformat[j++] = format[i++];
101:       newformat[j++] = format[i++];
102:     } else if (format[i] == '%') {
103:       if (format[i + 1] == 'g') {
104:         newformat[j++] = '[';
105:         newformat[j++] = '|';
106:       }
107:       /* Find the letter */
108:       for (; format[i] && format[i] <= '9'; i++) newformat[j++] = format[i];
109:       switch (format[i]) {
110:       case 'D':
111: #if !defined(PETSC_USE_64BIT_INDICES)
112:         newformat[j++] = 'd';
113: #else
114:         newformat[j++] = 'l';
115:         newformat[j++] = 'l';
116:         newformat[j++] = 'd';
117: #endif
118:         break;
119:       case 'g':
120:         newformat[j++] = format[i];
121:         if (format[i - 1] == '%') {
122:           newformat[j++] = '|';
123:           newformat[j++] = ']';
124:         }
125:         break;
126:       case 'G':
127:         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "%%G format is no longer supported, use %%g and cast the argument to double");
128:       case 'F':
129:         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "%%F format is no longer supported, use %%f and cast the argument to double");
130:       default:
131:         newformat[j++] = format[i];
132:         break;
133:       }
134:       i++;
135:     } else newformat[j++] = format[i++];
136:   }
137:   newformat[j] = 0;
138:   return 0;
139: }

141: #define PETSCDEFAULTBUFFERSIZE 8 * 1024

143: /*@C
144:      PetscVSNPrintf - The PETSc version of vsnprintf(). Converts a PETSc format string into a standard C format string and then puts all the
145:        function arguments into a string using the format statement.

147:    Input Parameters:
148: +   str - location to put result
149: .   len - the amount of space in str
150: +   format - the PETSc format string
151: -   fullLength - the amount of space in str actually used.

153:     Developer Note:
154:     this function may be called from an error handler, if an error occurs when it is called by the error handler than likely
155:       a recursion will occur and possible crash.

157:  Level: developer

159: .seealso: `PetscVSNPrintf()`, `PetscErrorPrintf()`, `PetscVPrintf()`
160: @*/
161: PetscErrorCode PetscVSNPrintf(char *str, size_t len, const char *format, size_t *fullLength, va_list Argp)
162: {
163:   char  *newformat = NULL;
164:   char   formatbuf[PETSCDEFAULTBUFFERSIZE];
165:   size_t newLength;
166:   int    flen;

168:   PetscFormatConvertGetSize(format, &newLength);
169:   if (newLength < sizeof(formatbuf)) {
170:     newformat = formatbuf;
171:     newLength = sizeof(formatbuf) - 1;
172:   } else {
173:     PetscMalloc1(newLength, &newformat);
174:   }
175:   PetscFormatConvert(format, newformat);
176: #if defined(PETSC_HAVE_VSNPRINTF)
177:   flen = vsnprintf(str, len, newformat, Argp);
178: #else
179:   #error "vsnprintf not found"
180: #endif
181:   if (newLength > sizeof(formatbuf) - 1) PetscFree(newformat);
182:   {
183:     PetscBool foundedot;
184:     size_t    cnt = 0, ncnt = 0, leng;
185:     PetscStrlen(str, &leng);
186:     if (leng > 4) {
187:       for (cnt = 0; cnt < leng - 4; cnt++) {
188:         if (str[cnt] == '[' && str[cnt + 1] == '|') {
189:           flen -= 4;
190:           cnt++;
191:           cnt++;
192:           foundedot = PETSC_FALSE;
193:           for (; cnt < leng - 1; cnt++) {
194:             if (str[cnt] == '|' && str[cnt + 1] == ']') {
195:               cnt++;
196:               if (!foundedot) str[ncnt++] = '.';
197:               ncnt--;
198:               break;
199:             } else {
200:               if (str[cnt] == 'e' || str[cnt] == '.') foundedot = PETSC_TRUE;
201:               str[ncnt++] = str[cnt];
202:             }
203:           }
204:         } else {
205:           str[ncnt] = str[cnt];
206:         }
207:         ncnt++;
208:       }
209:       while (cnt < leng) {
210:         str[ncnt] = str[cnt];
211:         ncnt++;
212:         cnt++;
213:       }
214:       str[ncnt] = 0;
215:     }
216:   }
217: #if defined(PETSC_HAVE_WINDOWS_H) && !defined(PETSC_HAVE__SET_OUTPUT_FORMAT)
218:   /* older Windows OS always produces e-+0np for floating point output; remove the extra 0 */
219:   {
220:     size_t cnt = 0, ncnt = 0, leng;
221:     PetscStrlen(str, &leng);
222:     if (leng > 5) {
223:       for (cnt = 0; cnt < leng - 4; cnt++) {
224:         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') {
225:           str[ncnt] = str[cnt];
226:           ncnt++;
227:           cnt++;
228:           str[ncnt] = str[cnt];
229:           ncnt++;
230:           cnt++;
231:           cnt++;
232:           str[ncnt] = str[cnt];
233:         } else {
234:           str[ncnt] = str[cnt];
235:         }
236:         ncnt++;
237:       }
238:       while (cnt < leng) {
239:         str[ncnt] = str[cnt];
240:         ncnt++;
241:         cnt++;
242:       }
243:       str[ncnt] = 0;
244:     }
245:   }
246: #endif
247:   if (fullLength) *fullLength = 1 + (size_t)flen;
248:   return 0;
249: }

251: /*@C
252:      PetscVFPrintf -  All PETSc standard out and error messages are sent through this function; so, in theory, this can
253:         can be replaced with something that does not simply write to a file.

255:       To use, write your own function for example,
256: $PetscErrorCode mypetscvfprintf(FILE *fd,const char format[],va_list Argp)
257: ${
259: $
260: $   if (fd != stdout && fd != stderr) {  handle regular files
261: $      CHKERR(PetscVFPrintfDefault(fd,format,Argp));
262: $  } else {
263: $     char   buff[BIG];
264: $     size_t length;
265: $     PetscVSNPrintf(buff,BIG,format,&length,Argp);
266: $     now send buff to whatever stream or whatever you want
267: $ }
268: $ return 0;
269: $}
270: then before the call to PetscInitialize() do the assignment
271: $    PetscVFPrintf = mypetscvfprintf;

273:       Note:
274:     For error messages this may be called by any process, for regular standard out it is
275:           called only by process 0 of a given communicator

277:       Developer Note:
278:     this could be called by an error handler, if that happens then a recursion of the error handler may occur
279:                        and a crash

281:   Level:  developer

283: .seealso: `PetscVSNPrintf()`, `PetscErrorPrintf()`
284: @*/
285: PetscErrorCode PetscVFPrintfDefault(FILE *fd, const char *format, va_list Argp)
286: {
287:   char   str[PETSCDEFAULTBUFFERSIZE];
288:   char  *buff = str;
289:   size_t fullLength;
290: #if defined(PETSC_HAVE_VA_COPY)
291:   va_list Argpcopy;
292: #endif

294: #if defined(PETSC_HAVE_VA_COPY)
295:   va_copy(Argpcopy, Argp);
296: #endif
297:   PetscVSNPrintf(str, sizeof(str), format, &fullLength, Argp);
298:   if (fullLength > sizeof(str)) {
299:     PetscMalloc1(fullLength, &buff);
300: #if defined(PETSC_HAVE_VA_COPY)
301:     PetscVSNPrintf(buff, fullLength, format, NULL, Argpcopy);
302: #else
303:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "C89 does not support va_copy() hence cannot print long strings with PETSc printing routines");
304: #endif
305:   }
306:   fprintf(fd, "%s", buff);
307:   fflush(fd);
308:   if (buff != str) PetscFree(buff);
309:   return 0;
310: }

312: /*@C
313:     PetscSNPrintf - Prints to a string of given length

315:     Not Collective

317:     Input Parameters:
318: +   str - the string to print to
319: .   len - the length of str
320: .   format - the usual printf() format string
321: -   ... - any arguments that are to be printed, each much have an appropriate symbol in the format argument

323:    Level: intermediate

325: .seealso: `PetscSynchronizedFlush()`, `PetscSynchronizedFPrintf()`, `PetscFPrintf()`, `PetscVSNPrintf()`,
326:           `PetscPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscVFPrintf()`
327: @*/
328: PetscErrorCode PetscSNPrintf(char *str, size_t len, const char format[], ...)
329: {
330:   size_t  fullLength;
331:   va_list Argp;

333:   va_start(Argp, format);
334:   PetscVSNPrintf(str, len, format, &fullLength, Argp);
335:   return 0;
336: }

338: /*@C
339:     PetscSNPrintfCount - Prints to a string of given length, returns count

341:     Not Collective

343:     Input Parameters:
344: +   str - the string to print to
345: .   len - the length of str
346: .   format - the usual printf() format string
347: -   ... - any arguments that are to be printed, each much have an appropriate symbol in the format argument

349:     Output Parameter:
350: .   countused - number of characters used

352:    Level: intermediate

354: .seealso: `PetscSynchronizedFlush()`, `PetscSynchronizedFPrintf()`, `PetscFPrintf()`, `PetscVSNPrintf()`,
355:           `PetscPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscSNPrintf()`, `PetscVFPrintf()`
356: @*/
357: PetscErrorCode PetscSNPrintfCount(char *str, size_t len, const char format[], size_t *countused, ...)
358: {
359:   va_list Argp;

361:   va_start(Argp, countused);
362:   PetscVSNPrintf(str, len, format, countused, Argp);
363:   return 0;
364: }

366: /* ----------------------------------------------------------------------- */

368: PrintfQueue petsc_printfqueue = NULL, petsc_printfqueuebase = NULL;
369: int         petsc_printfqueuelength = 0;

371: /*@C
372:     PetscSynchronizedPrintf - Prints synchronized output from several processors.
373:     Output of the first processor is followed by that of the second, etc.

375:     Not Collective

377:     Input Parameters:
378: +   comm - the communicator
379: -   format - the usual printf() format string

381:    Level: intermediate

383:     Note:
384:     REQUIRES a call to `PetscSynchronizedFlush()` by all the processes after the completion of the calls to `PetscSynchronizedPrintf()` for the information
385:     from all the processors to be printed.

387:     Fortran Note:
388:     The call sequence is `PetscSynchronizedPrintf`(MPI_Comm, character(*), PetscErrorCode ierr) from Fortran.
389:     That is, you can only pass a single character string from Fortran.

391: .seealso: `PetscSynchronizedFlush()`, `PetscSynchronizedFPrintf()`, `PetscFPrintf()`,
392:           `PetscPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIISynchronizedPrintf()`
393: @*/
394: PetscErrorCode PetscSynchronizedPrintf(MPI_Comm comm, const char format[], ...)
395: {
396:   PetscMPIInt rank;

399:   MPI_Comm_rank(comm, &rank);

401:   /* First processor prints immediately to stdout */
402:   if (rank == 0) {
403:     va_list Argp;
404:     va_start(Argp, format);
405:     (*PetscVFPrintf)(PETSC_STDOUT, format, Argp);
406:     if (petsc_history) {
407:       va_start(Argp, format);
408:       (*PetscVFPrintf)(petsc_history, format, Argp);
409:     }
410:     va_end(Argp);
411:   } else { /* other processors add to local queue */
412:     va_list     Argp;
413:     PrintfQueue next;
414:     size_t      fullLength = PETSCDEFAULTBUFFERSIZE;

416:     PetscNew(&next);
417:     if (petsc_printfqueue) {
418:       petsc_printfqueue->next = next;
419:       petsc_printfqueue       = next;
420:       petsc_printfqueue->next = NULL;
421:     } else petsc_printfqueuebase = petsc_printfqueue = next;
422:     petsc_printfqueuelength++;
423:     next->size   = 0;
424:     next->string = NULL;
425:     while (fullLength >= next->size) {
426:       next->size = fullLength + 1;
427:       PetscFree(next->string);
428:       PetscMalloc1(next->size, &next->string);
429:       va_start(Argp, format);
430:       PetscArrayzero(next->string, next->size);
431:       PetscVSNPrintf(next->string, next->size, format, &fullLength, Argp);
432:       va_end(Argp);
433:     }
434:   }
435:   return 0;
436: }

438: /*@C
439:     PetscSynchronizedFPrintf - Prints synchronized output to the specified file from
440:     several processors.  Output of the first processor is followed by that of the
441:     second, etc.

443:     Not Collective

445:     Input Parameters:
446: +   comm - the communicator
447: .   fd - the file pointer
448: -   format - the usual printf() format string

450:     Level: intermediate

452:     Note:
453:     REQUIRES a intervening call to `PetscSynchronizedFlush()` for the information
454:     from all the processors to be printed.

456: .seealso: `PetscSynchronizedPrintf()`, `PetscSynchronizedFlush()`, `PetscFPrintf()`,
457:           `PetscFOpen()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIPrintf()`
458: @*/
459: PetscErrorCode PetscSynchronizedFPrintf(MPI_Comm comm, FILE *fp, const char format[], ...)
460: {
461:   PetscMPIInt rank;

464:   MPI_Comm_rank(comm, &rank);

466:   /* First processor prints immediately to fp */
467:   if (rank == 0) {
468:     va_list Argp;
469:     va_start(Argp, format);
470:     (*PetscVFPrintf)(fp, format, Argp);
471:     if (petsc_history && (fp != petsc_history)) {
472:       va_start(Argp, format);
473:       (*PetscVFPrintf)(petsc_history, format, Argp);
474:     }
475:     va_end(Argp);
476:   } else { /* other processors add to local queue */
477:     va_list     Argp;
478:     PrintfQueue next;
479:     size_t      fullLength = PETSCDEFAULTBUFFERSIZE;

481:     PetscNew(&next);
482:     if (petsc_printfqueue) {
483:       petsc_printfqueue->next = next;
484:       petsc_printfqueue       = next;
485:       petsc_printfqueue->next = NULL;
486:     } else petsc_printfqueuebase = petsc_printfqueue = next;
487:     petsc_printfqueuelength++;
488:     next->size   = 0;
489:     next->string = NULL;
490:     while (fullLength >= next->size) {
491:       next->size = fullLength + 1;
492:       PetscFree(next->string);
493:       PetscMalloc1(next->size, &next->string);
494:       va_start(Argp, format);
495:       PetscArrayzero(next->string, next->size);
496:       PetscVSNPrintf(next->string, next->size, format, &fullLength, Argp);
497:       va_end(Argp);
498:     }
499:   }
500:   return 0;
501: }

503: /*@C
504:     PetscSynchronizedFlush - Flushes to the screen output from all processors
505:     involved in previous `PetscSynchronizedPrintf()`/`PetscSynchronizedFPrintf()` calls.

507:     Collective

509:     Input Parameters:
510: +   comm - the communicator
511: -   fd - the file pointer (valid on process 0 of the communicator)

513:     Level: intermediate

515:     Note:
516:     If `PetscSynchronizedPrintf()` and/or `PetscSynchronizedFPrintf()` are called with
517:     different MPI communicators there must be an intervening call to `PetscSynchronizedFlush()` between the calls with different MPI communicators.

519:     Fortran Note:
520:     Pass `PETSC_STDOUT` if the flush is for standard out; otherwise pass a value obtained from `PetscFOpen()`

522: .seealso: `PetscSynchronizedPrintf()`, `PetscFPrintf()`, `PetscPrintf()`, `PetscViewerASCIIPrintf()`,
523:           `PetscViewerASCIISynchronizedPrintf()`
524: @*/
525: PetscErrorCode PetscSynchronizedFlush(MPI_Comm comm, FILE *fd)
526: {
527:   PetscMPIInt rank, size, tag, i, j, n = 0, dummy = 0;
528:   char       *message;
529:   MPI_Status  status;

531:   PetscCommDuplicate(comm, &comm, &tag);
532:   MPI_Comm_rank(comm, &rank);
533:   MPI_Comm_size(comm, &size);

535:   /* First processor waits for messages from all other processors */
536:   if (rank == 0) {
537:     if (!fd) fd = PETSC_STDOUT;
538:     for (i = 1; i < size; i++) {
539:       /* to prevent a flood of messages to process zero, request each message separately */
540:       MPI_Send(&dummy, 1, MPI_INT, i, tag, comm);
541:       MPI_Recv(&n, 1, MPI_INT, i, tag, comm, &status);
542:       for (j = 0; j < n; j++) {
543:         PetscMPIInt size = 0;

545:         MPI_Recv(&size, 1, MPI_INT, i, tag, comm, &status);
546:         PetscMalloc1(size, &message);
547:         MPI_Recv(message, size, MPI_CHAR, i, tag, comm, &status);
548:         PetscFPrintf(comm, fd, "%s", message);
549:         PetscFree(message);
550:       }
551:     }
552:   } else { /* other processors send queue to processor 0 */
553:     PrintfQueue next = petsc_printfqueuebase, previous;

555:     MPI_Recv(&dummy, 1, MPI_INT, 0, tag, comm, &status);
556:     MPI_Send(&petsc_printfqueuelength, 1, MPI_INT, 0, tag, comm);
557:     for (i = 0; i < petsc_printfqueuelength; i++) {
558:       MPI_Send(&next->size, 1, MPI_INT, 0, tag, comm);
559:       MPI_Send(next->string, next->size, MPI_CHAR, 0, tag, comm);
560:       previous = next;
561:       next     = next->next;
562:       PetscFree(previous->string);
563:       PetscFree(previous);
564:     }
565:     petsc_printfqueue       = NULL;
566:     petsc_printfqueuelength = 0;
567:   }
568:   PetscCommDestroy(&comm);
569:   return 0;
570: }

572: /* ---------------------------------------------------------------------------------------*/

574: /*@C
575:     PetscFPrintf - Prints to a file, only from the first
576:     processor in the communicator.

578:     Not Collective; No Fortran Support

580:     Input Parameters:
581: +   comm - the communicator
582: .   fd - the file pointer
583: -   format - the usual printf() format string

585:     Level: intermediate

587: .seealso: `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
588:           `PetscViewerASCIISynchronizedPrintf()`, `PetscSynchronizedFlush()`
589: @*/
590: PetscErrorCode PetscFPrintf(MPI_Comm comm, FILE *fd, const char format[], ...)
591: {
592:   PetscMPIInt rank;

595:   MPI_Comm_rank(comm, &rank);
596:   if (rank == 0) {
597:     va_list Argp;
598:     va_start(Argp, format);
599:     (*PetscVFPrintf)(fd, format, Argp);
600:     if (petsc_history && (fd != petsc_history)) {
601:       va_start(Argp, format);
602:       (*PetscVFPrintf)(petsc_history, format, Argp);
603:     }
604:     va_end(Argp);
605:   }
606:   return 0;
607: }

609: /*@C
610:     PetscPrintf - Prints to standard out, only from the first
611:     processor in the communicator. Calls from other processes are ignored.

613:     Not Collective

615:     Input Parameters:
616: +   comm - the communicator
617: -   format - the usual printf() format string

619:     Level: intermediate

621:     Note:
622:     Deprecated information: `PetscPrintf()` supports some format specifiers that are unique to PETSc.
623:     See the manual page for `PetscFormatConvert()` for details.

625:     Fortran Note:
626:     The call sequence is `PetscPrintf`(MPI_Comm, character(*), `PetscErrorCode` ierr) from Fortran.
627:     That is, you can only pass a single character string from Fortran.

629: .seealso: `PetscFPrintf()`, `PetscSynchronizedPrintf()`, `PetscFormatConvert()`
630: @*/
631: PetscErrorCode PetscPrintf(MPI_Comm comm, const char format[], ...)
632: {
633:   PetscMPIInt rank;

636:   MPI_Comm_rank(comm, &rank);
637:   if (rank == 0) {
638:     va_list Argp;
639:     va_start(Argp, format);
640:     (*PetscVFPrintf)(PETSC_STDOUT, format, Argp);
641:     if (petsc_history) {
642:       va_start(Argp, format);
643:       (*PetscVFPrintf)(petsc_history, format, Argp);
644:     }
645:     va_end(Argp);
646:   }
647:   return 0;
648: }

650: PetscErrorCode PetscHelpPrintfDefault(MPI_Comm comm, const char format[], ...)
651: {
652:   PetscMPIInt rank;

655:   MPI_Comm_rank(comm, &rank);
656:   if (rank == 0) {
657:     va_list Argp;
658:     va_start(Argp, format);
659:     (*PetscVFPrintf)(PETSC_STDOUT, format, Argp);
660:     if (petsc_history) {
661:       va_start(Argp, format);
662:       (*PetscVFPrintf)(petsc_history, format, Argp);
663:     }
664:     va_end(Argp);
665:   }
666:   return 0;
667: }

669: /* ---------------------------------------------------------------------------------------*/

671: /*@C
672:     PetscSynchronizedFGets - Several processors all get the same line from a file.

674:     Collective

676:     Input Parameters:
677: +   comm - the communicator
678: .   fd - the file pointer
679: -   len - the length of the output buffer

681:     Output Parameter:
682: .   string - the line read from the file, at end of file string[0] == 0

684:     Level: intermediate

686: .seealso: `PetscSynchronizedPrintf()`, `PetscSynchronizedFlush()`,
687:           `PetscFOpen()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIPrintf()`
688: @*/
689: PetscErrorCode PetscSynchronizedFGets(MPI_Comm comm, FILE *fp, size_t len, char string[])
690: {
691:   PetscMPIInt rank;

693:   MPI_Comm_rank(comm, &rank);

695:   if (rank == 0) {
696:     char *ptr = fgets(string, len, fp);

698:     if (!ptr) {
699:       string[0] = 0;
701:     }
702:   }
703:   MPI_Bcast(string, len, MPI_BYTE, 0, comm);
704:   return 0;
705: }

707: /*@C
708:      PetscFormatStrip - Takes a PETSc format string and removes all numerical modifiers to % operations

710:    Input Parameters:
711: .   format - the PETSc format string

713:  Level: developer

715: @*/
716: PetscErrorCode PetscFormatStrip(char *format)
717: {
718:   size_t loc1 = 0, loc2 = 0;

720:   while (format[loc2]) {
721:     if (format[loc2] == '%') {
722:       format[loc1++] = format[loc2++];
723:       while (format[loc2] && ((format[loc2] >= '0' && format[loc2] <= '9') || format[loc2] == '.')) loc2++;
724:     }
725:     format[loc1++] = format[loc2++];
726:   }
727:   return 0;
728: }

730: PetscErrorCode PetscFormatRealArray(char buf[], size_t len, const char *fmt, PetscInt n, const PetscReal x[])
731: {
732:   PetscInt i;
733:   size_t   left, count;
734:   char    *p;

736:   for (i = 0, p = buf, left = len; i < n; i++) {
737:     PetscSNPrintfCount(p, left, fmt, &count, (double)x[i]);
739:     left -= count;
740:     p += count - 1;
741:     *p++ = ' ';
742:   }
743:   p[i ? 0 : -1] = 0;
744:   return 0;
745: }