Actual source code: mprint.c
petsc-3.7.3 2016-08-01
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: extern 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 = 0;
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 = 0;
24: /*
25: Return the maximum expected new size of the format
26: */
27: #define PETSC_MAX_LENGTH_FORMAT(l) (l+l/8)
31: /*@C
32: PetscFormatConvert - Takes a PETSc format string and converts it to a reqular C format string
34: Input Parameters:
35: + format - the PETSc format string
36: . newformat - the location to put the standard C format string values
37: - size - the length of newformat
39: Note: this exists so we can have the same code when PetscInt is either int or long long and PetscScalar is either __float128, double, or float
41: Level: developer
43: @*/
44: PetscErrorCode PetscFormatConvert(const char *format,char *newformat,size_t size)
45: {
46: PetscInt i = 0,j = 0;
49: while (format[i] && j < (PetscInt)size-1) {
50: if (format[i] == '%' && format[i+1] == '%') {
51: newformat[j++] = format[i++];
52: newformat[j++] = format[i++];
53: } else if (format[i] == '%') {
54: if (format[i+1] == 'g') {
55: newformat[j++] = '[';
56: newformat[j++] = '|';
57: }
58: /* Find the letter */
59: for (; format[i] && format[i] <= '9'; i++) newformat[j++] = format[i];
60: switch (format[i]) {
61: case 'D':
62: #if !defined(PETSC_USE_64BIT_INDICES)
63: newformat[j++] = 'd';
64: #else
65: newformat[j++] = 'l';
66: newformat[j++] = 'l';
67: newformat[j++] = 'd';
68: #endif
69: break;
70: case 'g':
71: newformat[j++] = format[i];
72: if (format[i-1] == '%') {
73: newformat[j++] = '|';
74: newformat[j++] = ']';
75: }
76: break;
77: case 'G':
78: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"%%G format is no longer supported, use %%g and cast the argument to double");
79: break;
80: case 'F':
81: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"%%F format is no longer supported, use %%f and cast the argument to double");
82: break;
83: default:
84: newformat[j++] = format[i];
85: break;
86: }
87: i++;
88: } else newformat[j++] = format[i++];
89: }
90: newformat[j] = 0;
91: return(0);
92: }
96: /*@C
97: PetscVSNPrintf - The PETSc version of vsnprintf(). Converts a PETSc format string into a standard C format string and then puts all the
98: function arguments into a string using the format statement.
100: Input Parameters:
101: + str - location to put result
102: . len - the amount of space in str
103: + format - the PETSc format string
104: - fullLength - the amount of space in str actually used.
106: Developer Notes: this function may be called from an error handler, if an error occurs when it is called by the error handler than likely
107: a recursion will occur and possible crash.
109: Level: developer
111: @*/
112: PetscErrorCode PetscVSNPrintf(char *str,size_t len,const char *format,size_t *fullLength,va_list Argp)
113: {
114: char *newformat;
115: char formatbuf[8*1024];
116: size_t oldLength,length;
120: PetscStrlen(format, &oldLength);
121: if (oldLength < 8*1024) {
122: newformat = formatbuf;
123: oldLength = 8*1024-1;
124: } else {
125: oldLength = PETSC_MAX_LENGTH_FORMAT(oldLength);
126: PetscMalloc1(oldLength, &newformat);
127: }
128: PetscFormatConvert(format,newformat,oldLength);
129: PetscStrlen(newformat, &length);
130: #if 0
131: if (length > len) newformat[len] = '\0';
132: #endif
133: #if defined(PETSC_HAVE_VSNPRINTF_CHAR)
134: (void) vsnprintf(str,len,newformat,(char*)Argp);
135: #elif defined(PETSC_HAVE_VSNPRINTF)
136: (void) vsnprintf(str,len,newformat,Argp);
137: #elif defined(PETSC_HAVE__VSNPRINTF)
138: (void) _vsnprintf(str,len,newformat,Argp);
139: #else
140: #error "vsnprintf not found"
141: #endif
142: if (oldLength >= 8*1024) {
143: PetscFree(newformat);
144: }
145: {
146: PetscBool foundedot;
147: size_t cnt = 0,ncnt = 0,leng;
148: PetscStrlen(str,&leng);
149: if (leng > 4) {
150: for (cnt=0; cnt<leng-4; cnt++) {
151: if (str[cnt] == '[' && str[cnt+1] == '|'){
152: cnt++; cnt++;
153: foundedot = PETSC_FALSE;
154: for (; cnt<leng-1; cnt++) {
155: if (str[cnt] == '|' && str[cnt+1] == ']'){
156: cnt++;
157: if (!foundedot) str[ncnt++] = '.';
158: ncnt--;
159: break;
160: } else {
161: if (str[cnt] == 'e' || str[cnt] == '.') foundedot = PETSC_TRUE;
162: str[ncnt++] = str[cnt];
163: }
164: }
165: } else {
166: str[ncnt] = str[cnt];
167: }
168: ncnt++;
169: }
170: while (cnt < leng) {
171: str[ncnt] = str[cnt]; ncnt++; cnt++;
172: }
173: str[ncnt] = 0;
174: }
175: }
176: #if defined(PETSC_HAVE_WINDOWS_H) && !defined(PETSC_HAVE__SET_OUTPUT_FORMAT)
177: /* older Windows OS always produces e-+0np for floating point output; remove the extra 0 */
178: {
179: size_t cnt = 0,ncnt = 0,leng;
180: PetscStrlen(str,&leng);
181: if (leng > 5) {
182: for (cnt=0; cnt<leng-4; cnt++) {
183: 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') {
184: str[ncnt] = str[cnt]; ncnt++; cnt++;
185: str[ncnt] = str[cnt]; ncnt++; cnt++; cnt++;
186: str[ncnt] = str[cnt];
187: } else {
188: str[ncnt] = str[cnt];
189: }
190: ncnt++;
191: }
192: while (cnt < leng) {
193: str[ncnt] = str[cnt]; ncnt++; cnt++;
194: }
195: str[ncnt] = 0;
196: }
197: }
198: #endif
199: if (fullLength) {
200: PetscStrlen(str,fullLength);
201: }
202: return(0);
203: }
207: /*@C
208: PetscVFPrintf - All PETSc standard out and error messages are sent through this function; so, in theory, this can
209: can be replaced with something that does not simply write to a file.
211: To use, write your own function for example,
212: $PetscErrorCode mypetscvfprintf(FILE *fd,const char format[],va_list Argp)
213: ${
215: $
217: $ if (fd != stdout && fd != stderr) { handle regular files
218: $ PetscVFPrintfDefault(fd,format,Argp);CHKERR(ierr);
219: $ } else {
220: $ char buff[BIG];
221: $ size_t length;
222: $ PetscVSNPrintf(buff,BIG,format,&length,Argp);
223: $ now send buff to whatever stream or whatever you want
224: $ }
225: $ return(0);
226: $}
227: then before the call to PetscInitialize() do the assignment
228: $ PetscVFPrintf = mypetscvfprintf;
230: Notes: For error messages this may be called by any process, for regular standard out it is
231: called only by process 0 of a given communicator
233: Developer Notes: this could be called by an error handler, if that happens then a recursion of the error handler may occur
234: and a crash
236: Level: developer
238: .seealso: PetscVSNPrintf(), PetscErrorPrintf()
240: @*/
241: PetscErrorCode PetscVFPrintfDefault(FILE *fd,const char *format,va_list Argp)
242: {
243: char str[8*1024];
247: PetscVSNPrintf(str,sizeof(str),format,NULL,Argp);
248: fprintf(fd,"%s",str);
249: fflush(fd);
250: return(0);
251: }
255: /*@C
256: PetscSNPrintf - Prints to a string of given length
258: Not Collective
260: Input Parameters:
261: + str - the string to print to
262: . len - the length of str
263: . format - the usual printf() format string
264: - any arguments
266: Level: intermediate
268: .seealso: PetscSynchronizedFlush(), PetscSynchronizedFPrintf(), PetscFPrintf(), PetscVSNPrintf(),
269: PetscPrintf(), PetscViewerASCIIPrintf(), PetscViewerASCIISynchronizedPrintf()
270: @*/
271: PetscErrorCode PetscSNPrintf(char *str,size_t len,const char format[],...)
272: {
274: size_t fullLength;
275: va_list Argp;
278: va_start(Argp,format);
279: PetscVSNPrintf(str,len,format,&fullLength,Argp);
280: return(0);
281: }
285: /*@C
286: PetscSNPrintfCount - Prints to a string of given length, returns count
288: Not Collective
290: Input Parameters:
291: + str - the string to print to
292: . len - the length of str
293: . format - the usual printf() format string
294: . countused - number of characters used
295: - any arguments
297: Level: intermediate
299: .seealso: PetscSynchronizedFlush(), PetscSynchronizedFPrintf(), PetscFPrintf(), PetscVSNPrintf(),
300: PetscPrintf(), PetscViewerASCIIPrintf(), PetscViewerASCIISynchronizedPrintf(), PetscSNPrintf()
301: @*/
302: PetscErrorCode PetscSNPrintfCount(char *str,size_t len,const char format[],size_t *countused,...)
303: {
305: va_list Argp;
308: va_start(Argp,countused);
309: PetscVSNPrintf(str,len,format,countused,Argp);
310: return(0);
311: }
313: /* ----------------------------------------------------------------------- */
315: PrintfQueue petsc_printfqueue = 0,petsc_printfqueuebase = 0;
316: int petsc_printfqueuelength = 0;
320: /*@C
321: PetscSynchronizedPrintf - Prints synchronized output from several processors.
322: Output of the first processor is followed by that of the second, etc.
324: Not Collective
326: Input Parameters:
327: + comm - the communicator
328: - format - the usual printf() format string
330: Level: intermediate
332: Notes:
333: REQUIRES a intervening call to PetscSynchronizedFlush() for the information
334: from all the processors to be printed.
336: Fortran Note:
337: The call sequence is PetscSynchronizedPrintf(MPI_Comm, character(*), PetscErrorCode ierr) from Fortran.
338: That is, you can only pass a single character string from Fortran.
340: .seealso: PetscSynchronizedFlush(), PetscSynchronizedFPrintf(), PetscFPrintf(),
341: PetscPrintf(), PetscViewerASCIIPrintf(), PetscViewerASCIISynchronizedPrintf()
342: @*/
343: PetscErrorCode PetscSynchronizedPrintf(MPI_Comm comm,const char format[],...)
344: {
346: PetscMPIInt rank;
349: if (comm == MPI_COMM_NULL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
350: MPI_Comm_rank(comm,&rank);
352: /* First processor prints immediately to stdout */
353: if (!rank) {
354: va_list Argp;
355: va_start(Argp,format);
356: (*PetscVFPrintf)(PETSC_STDOUT,format,Argp);
357: if (petsc_history) {
358: va_start(Argp,format);
359: (*PetscVFPrintf)(petsc_history,format,Argp);
360: }
361: va_end(Argp);
362: } else { /* other processors add to local queue */
363: va_list Argp;
364: PrintfQueue next;
365: size_t fullLength = 8191;
367: PetscNew(&next);
368: if (petsc_printfqueue) {
369: petsc_printfqueue->next = next;
370: petsc_printfqueue = next;
371: petsc_printfqueue->next = 0;
372: } else petsc_printfqueuebase = petsc_printfqueue = next;
373: petsc_printfqueuelength++;
374: next->size = -1;
375: while ((PetscInt)fullLength >= next->size) {
376: next->size = fullLength+1;
378: PetscMalloc1(next->size, &next->string);
379: va_start(Argp,format);
380: PetscMemzero(next->string,next->size);
381: PetscVSNPrintf(next->string,next->size,format, &fullLength,Argp);
382: va_end(Argp);
383: }
384: }
385: return(0);
386: }
390: /*@C
391: PetscSynchronizedFPrintf - Prints synchronized output to the specified file from
392: several processors. Output of the first processor is followed by that of the
393: second, etc.
395: Not Collective
397: Input Parameters:
398: + comm - the communicator
399: . fd - the file pointer
400: - format - the usual printf() format string
402: Level: intermediate
404: Notes:
405: REQUIRES a intervening call to PetscSynchronizedFlush() for the information
406: from all the processors to be printed.
408: .seealso: PetscSynchronizedPrintf(), PetscSynchronizedFlush(), PetscFPrintf(),
409: PetscFOpen(), PetscViewerASCIISynchronizedPrintf(), PetscViewerASCIIPrintf()
411: @*/
412: PetscErrorCode PetscSynchronizedFPrintf(MPI_Comm comm,FILE *fp,const char format[],...)
413: {
415: PetscMPIInt rank;
418: if (comm == MPI_COMM_NULL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
419: MPI_Comm_rank(comm,&rank);
421: /* First processor prints immediately to fp */
422: if (!rank) {
423: va_list Argp;
424: va_start(Argp,format);
425: (*PetscVFPrintf)(fp,format,Argp);
426: if (petsc_history && (fp !=petsc_history)) {
427: va_start(Argp,format);
428: (*PetscVFPrintf)(petsc_history,format,Argp);
429: }
430: va_end(Argp);
431: } else { /* other processors add to local queue */
432: va_list Argp;
433: PrintfQueue next;
434: size_t fullLength = 8191;
435: PetscNew(&next);
436: if (petsc_printfqueue) {
437: petsc_printfqueue->next = next;
438: petsc_printfqueue = next;
439: petsc_printfqueue->next = 0;
440: } else petsc_printfqueuebase = petsc_printfqueue = next;
441: petsc_printfqueuelength++;
442: next->size = -1;
443: while ((PetscInt)fullLength >= next->size) {
444: next->size = fullLength+1;
445: PetscMalloc1(next->size, &next->string);
446: va_start(Argp,format);
447: PetscMemzero(next->string,next->size);
448: PetscVSNPrintf(next->string,next->size,format,&fullLength,Argp);
449: va_end(Argp);
450: }
451: }
452: return(0);
453: }
457: /*@C
458: PetscSynchronizedFlush - Flushes to the screen output from all processors
459: involved in previous PetscSynchronizedPrintf() calls.
461: Collective on MPI_Comm
463: Input Parameters:
464: + comm - the communicator
465: - fd - the file pointer (valid on process 0 of the communicator)
467: Level: intermediate
469: Notes:
470: Usage of PetscSynchronizedPrintf() and PetscSynchronizedFPrintf() with
471: different MPI communicators REQUIRES an intervening call to PetscSynchronizedFlush().
473: .seealso: PetscSynchronizedPrintf(), PetscFPrintf(), PetscPrintf(), PetscViewerASCIIPrintf(),
474: PetscViewerASCIISynchronizedPrintf()
475: @*/
476: PetscErrorCode PetscSynchronizedFlush(MPI_Comm comm,FILE *fd)
477: {
479: PetscMPIInt rank,size,tag,i,j,n = 0,dummy = 0;
480: char *message;
481: MPI_Status status;
484: PetscCommDuplicate(comm,&comm,&tag);
485: MPI_Comm_rank(comm,&rank);
486: MPI_Comm_size(comm,&size);
488: /* First processor waits for messages from all other processors */
489: if (!rank) {
490: if (!fd) fd = PETSC_STDOUT;
491: for (i=1; i<size; i++) {
492: /* to prevent a flood of messages to process zero, request each message separately */
493: MPI_Send(&dummy,1,MPI_INT,i,tag,comm);
494: MPI_Recv(&n,1,MPI_INT,i,tag,comm,&status);
495: for (j=0; j<n; j++) {
496: PetscMPIInt size = 0;
498: MPI_Recv(&size,1,MPI_INT,i,tag,comm,&status);
499: PetscMalloc1(size, &message);
500: MPI_Recv(message,size,MPI_CHAR,i,tag,comm,&status);
501: PetscFPrintf(comm,fd,"%s",message);
502: PetscFree(message);
503: }
504: }
505: } else { /* other processors send queue to processor 0 */
506: PrintfQueue next = petsc_printfqueuebase,previous;
508: MPI_Recv(&dummy,1,MPI_INT,0,tag,comm,&status);
509: MPI_Send(&petsc_printfqueuelength,1,MPI_INT,0,tag,comm);
510: for (i=0; i<petsc_printfqueuelength; i++) {
511: MPI_Send(&next->size,1,MPI_INT,0,tag,comm);
512: MPI_Send(next->string,next->size,MPI_CHAR,0,tag,comm);
513: previous = next;
514: next = next->next;
515: PetscFree(previous->string);
516: PetscFree(previous);
517: }
518: petsc_printfqueue = 0;
519: petsc_printfqueuelength = 0;
520: }
521: PetscCommDestroy(&comm);
522: return(0);
523: }
525: /* ---------------------------------------------------------------------------------------*/
529: /*@C
530: PetscFPrintf - Prints to a file, only from the first
531: processor in the communicator.
533: Not Collective
535: Input Parameters:
536: + comm - the communicator
537: . fd - the file pointer
538: - format - the usual printf() format string
540: Level: intermediate
542: Fortran Note:
543: This routine is not supported in Fortran.
545: Concepts: printing^in parallel
546: Concepts: printf^in parallel
548: .seealso: PetscPrintf(), PetscSynchronizedPrintf(), PetscViewerASCIIPrintf(),
549: PetscViewerASCIISynchronizedPrintf(), PetscSynchronizedFlush()
550: @*/
551: PetscErrorCode PetscFPrintf(MPI_Comm comm,FILE* fd,const char format[],...)
552: {
554: PetscMPIInt rank;
557: if (comm == MPI_COMM_NULL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
558: MPI_Comm_rank(comm,&rank);
559: if (!rank) {
560: va_list Argp;
561: va_start(Argp,format);
562: (*PetscVFPrintf)(fd,format,Argp);
563: if (petsc_history && (fd !=petsc_history)) {
564: va_start(Argp,format);
565: (*PetscVFPrintf)(petsc_history,format,Argp);
566: }
567: va_end(Argp);
568: }
569: return(0);
570: }
574: /*@C
575: PetscPrintf - Prints to standard out, only from the first
576: processor in the communicator. Calls from other processes are ignored.
578: Not Collective
580: Input Parameters:
581: + comm - the communicator
582: - format - the usual printf() format string
584: Level: intermediate
586: Fortran Note:
587: The call sequence is PetscPrintf(MPI_Comm, character(*), PetscErrorCode ierr) from Fortran.
588: That is, you can only pass a single character string from Fortran.
590: Concepts: printing^in parallel
591: Concepts: printf^in parallel
593: .seealso: PetscFPrintf(), PetscSynchronizedPrintf()
594: @*/
595: PetscErrorCode PetscPrintf(MPI_Comm comm,const char format[],...)
596: {
598: PetscMPIInt rank;
601: if (comm == MPI_COMM_NULL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
602: MPI_Comm_rank(comm,&rank);
603: if (!rank) {
604: va_list Argp;
605: va_start(Argp,format);
606: (*PetscVFPrintf)(PETSC_STDOUT,format,Argp);
607: if (petsc_history) {
608: va_start(Argp,format);
609: (*PetscVFPrintf)(petsc_history,format,Argp);
610: }
611: va_end(Argp);
612: }
613: return(0);
614: }
616: /* ---------------------------------------------------------------------------------------*/
619: /*@C
620: PetscHelpPrintf - All PETSc help messages are passing through this function. You can change how help messages are printed by
621: replacinng it with something that does not simply write to a stdout.
623: To use, write your own function for example,
624: $PetscErrorCode mypetschelpprintf(MPI_Comm comm,const char format[],....)
625: ${
626: $ return(0);
627: $}
628: then before the call to PetscInitialize() do the assignment
629: $ PetscHelpPrintf = mypetschelpprintf;
631: Note: the default routine used is called PetscHelpPrintfDefault().
633: Level: developer
635: .seealso: PetscVSNPrintf(), PetscVFPrintf(), PetscErrorPrintf()
636: @*/
637: PetscErrorCode PetscHelpPrintfDefault(MPI_Comm comm,const char format[],...)
638: {
640: PetscMPIInt rank;
643: if (comm == MPI_COMM_NULL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
644: MPI_Comm_rank(comm,&rank);
645: if (!rank) {
646: va_list Argp;
647: va_start(Argp,format);
648: (*PetscVFPrintf)(PETSC_STDOUT,format,Argp);
649: if (petsc_history) {
650: va_start(Argp,format);
651: (*PetscVFPrintf)(petsc_history,format,Argp);
652: }
653: va_end(Argp);
654: }
655: return(0);
656: }
658: /* ---------------------------------------------------------------------------------------*/
663: /*@C
664: PetscSynchronizedFGets - Several processors all get the same line from a file.
666: Collective on MPI_Comm
668: Input Parameters:
669: + comm - the communicator
670: . fd - the file pointer
671: - len - the length of the output buffer
673: Output Parameter:
674: . string - the line read from the file, at end of file string[0] == 0
676: Level: intermediate
678: .seealso: PetscSynchronizedPrintf(), PetscSynchronizedFlush(),
679: PetscFOpen(), PetscViewerASCIISynchronizedPrintf(), PetscViewerASCIIPrintf()
681: @*/
682: PetscErrorCode PetscSynchronizedFGets(MPI_Comm comm,FILE *fp,size_t len,char string[])
683: {
685: PetscMPIInt rank;
688: MPI_Comm_rank(comm,&rank);
690: if (!rank) {
691: char *ptr = fgets(string, len, fp);
693: if (!ptr) {
694: string[0] = 0;
695: if (!feof(fp)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from file: %d", errno);
696: }
697: }
698: MPI_Bcast(string,len,MPI_BYTE,0,comm);
699: return(0);
700: }
702: #if defined(PETSC_HAVE_CLOSURES)
703: int (^SwiftClosure)(const char*) = 0;
707: PetscErrorCode PetscVFPrintfToString(FILE *fd,const char format[],va_list Argp)
708: {
712: if (fd != stdout && fd != stderr) { /* handle regular files */
713: PetscVFPrintfDefault(fd,format,Argp);
714: } else {
715: size_t len=8*1024,length;
716: char buf[len];
718: PetscVSNPrintf(buf,len,format,&length,Argp);
719: SwiftClosure(buf);
720: }
721: return(0);
722: }
724: /*
725: Provide a Swift function that processes all the PETSc calls to PetscVFPrintf()
726: */
727: PetscErrorCode PetscVFPrintfSetClosure(int (^closure)(const char*))
728: {
729: PetscVFPrintf = PetscVFPrintfToString;
730: SwiftClosure = closure;
731: return 0;
732: }
733: #endif
735: #if defined(PETSC_HAVE_MATLAB_ENGINE)
736: #include <mex.h>
739: PetscErrorCode PetscVFPrintf_Matlab(FILE *fd,const char format[],va_list Argp)
740: {
744: if (fd != stdout && fd != stderr) { /* handle regular files */
745: PetscVFPrintfDefault(fd,format,Argp);
746: } else {
747: size_t len=8*1024,length;
748: char buf[len];
750: PetscVSNPrintf(buf,len,format,&length,Argp);
751: mexPrintf("%s",buf);
752: }
753: return(0);
754: }
755: #endif
759: /*@C
760: PetscFormatStrip - Takes a PETSc format string and removes all numerical modifiers to % operations
762: Input Parameters:
763: . format - the PETSc format string
765: Level: developer
767: @*/
768: PetscErrorCode PetscFormatStrip(char *format)
769: {
770: size_t loc1 = 0, loc2 = 0;
773: while (format[loc2]) {
774: if (format[loc2] == '%') {
775: format[loc1++] = format[loc2++];
776: while (format[loc2] && ((format[loc2] >= '0' && format[loc2] <= '9') || format[loc2] == '.')) loc2++;
777: }
778: format[loc1++] = format[loc2++];
779: }
780: return(0);
781: }