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: }