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