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