xref: /petsc/src/sys/fileio/mprint.c (revision 84df9cb40eca90ea9b18a456fab7a4ecc7f6c1a4)
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;
23 /*
24      Used to output to Zope
25 */
26 FILE *PETSC_ZOPEFD = 0;
27 
28 /*
29      Return the maximum expected new size of the format
30 */
31 #define PETSC_MAX_LENGTH_FORMAT(l) (l+l/8)
32 
33 #undef __FUNCT__
34 #define __FUNCT__ "PetscFormatConvert"
35 /*@C
36      PetscFormatConvert - Takes a PETSc format string and converts it to a reqular C format string
37 
38    Input Parameters:
39 +   format - the PETSc format string
40 .   newformat - the location to put the standard C format string values
41 -   size - the length of newformat
42 
43     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
44 
45  Level: developer
46 
47 @*/
48 PetscErrorCode  PetscFormatConvert(const char *format,char *newformat,size_t size)
49 {
50   PetscInt i = 0,j = 0;
51 
52   PetscFunctionBegin;
53   while (format[i] && j < (PetscInt)size-1) {
54     if (format[i] == '%' && format[i+1] != '%') {
55       /* Find the letter */
56       for ( ; format[i] && format[i] <= '9'; i++) newformat[j++] = format[i];
57       switch (format[i]) {
58       case 'D':
59 #if !defined(PETSC_USE_64BIT_INDICES)
60         newformat[j++] = 'd';
61 #else
62         newformat[j++] = 'l';
63         newformat[j++] = 'l';
64         newformat[j++] = 'd';
65 #endif
66         break;
67       case 'G':
68 #if defined(PETSC_USE_REAL_DOUBLE) || defined(PETSC_USE_REAL_SINGLE)
69         newformat[j++] = 'g';
70 #elif defined(PETSC_USE_REAL___FLOAT128)
71         newformat[j++] = 'Q';
72         newformat[j++] = 'g';
73 #endif
74         break;
75       case 'F':
76 #if defined(PETSC_USE_REAL_DOUBLE) || defined(PETSC_USE_REAL_SINGLE)
77         newformat[j++] = 'f';
78 #elif defined(PETSC_USE_REAL_LONG_DOUBLE)
79         newformat[j++] = 'L';
80         newformat[j++] = 'f';
81 #elif defined(PETSC_USE_REAL___FLOAT128)
82         newformat[j++] = 'Q';
83         newformat[j++] = 'f';
84 #endif
85         break;
86       default:
87         newformat[j++] = format[i];
88         break;
89       }
90       i++;
91     } else {
92       newformat[j++] = format[i++];
93     }
94   }
95   newformat[j] = 0;
96   PetscFunctionReturn(0);
97 }
98 
99 #undef __FUNCT__
100 #define __FUNCT__ "PetscVSNPrintf"
101 /*@C
102      PetscVSNPrintf - The PETSc version of vsnprintf(). Converts a PETSc format string into a standard C format string and then puts all the
103        function arguments into a string using the format statement.
104 
105    Input Parameters:
106 +   str - location to put result
107 .   len - the amount of space in str
108 +   format - the PETSc format string
109 -   fullLength - the amount of space in str actually used.
110 
111     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
112       a recursion will occur and possible crash.
113 
114  Level: developer
115 
116 @*/
117 PetscErrorCode  PetscVSNPrintf(char *str,size_t len,const char *format,size_t *fullLength,va_list Argp)
118 {
119   char          *newformat;
120   char           formatbuf[8*1024];
121   size_t         oldLength,length;
122   int            fullLengthInt;
123   PetscErrorCode ierr;
124 
125   PetscFunctionBegin;
126   ierr = PetscStrlen(format, &oldLength);CHKERRQ(ierr);
127   if (oldLength < 8*1024) {
128     newformat = formatbuf;
129     oldLength = 8*1024-1;
130   } else {
131     oldLength = PETSC_MAX_LENGTH_FORMAT(oldLength);
132     ierr = PetscMalloc(oldLength * sizeof(char), &newformat);CHKERRQ(ierr);
133   }
134   PetscFormatConvert(format,newformat,oldLength);
135   ierr = PetscStrlen(newformat, &length);CHKERRQ(ierr);
136 #if 0
137   if (length > len) {
138     newformat[len] = '\0';
139   }
140 #endif
141 #if defined(PETSC_HAVE_VSNPRINTF_CHAR)
142   fullLengthInt = vsnprintf(str,len,newformat,(char *)Argp);
143 #elif defined(PETSC_HAVE_VSNPRINTF)
144   fullLengthInt = vsnprintf(str,len,newformat,Argp);
145 #elif defined(PETSC_HAVE__VSNPRINTF)
146   fullLengthInt = _vsnprintf(str,len,newformat,Argp);
147 #else
148 #error "vsnprintf not found"
149 #endif
150   if (fullLengthInt < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"vsnprintf() failed");
151   if (fullLength) *fullLength = (size_t)fullLengthInt;
152   if (oldLength >= 8*1024) {
153     ierr = PetscFree(newformat);CHKERRQ(ierr);
154   }
155   PetscFunctionReturn(0);
156 }
157 
158 #undef __FUNCT__
159 #define __FUNCT__ "PetscZopeLog"
160 PetscErrorCode  PetscZopeLog(const char *format,va_list Argp)
161 {
162   /* no malloc since may be called by error handler */
163   char        newformat[8*1024];
164   char        log[8*1024];
165   char        logstart[] = " <<<log>>>";
166   size_t      len,formatlen;
167 
168   PetscFormatConvert(format,newformat,8*1024);
169   PetscStrlen(logstart, &len);
170   PetscMemcpy(log, logstart, len);
171   PetscStrlen(newformat, &formatlen);
172   PetscMemcpy(&(log[len]), newformat, formatlen);
173   if (PETSC_ZOPEFD){
174 #if defined(PETSC_HAVE_VFPRINTF_CHAR)
175     vfprintf(PETSC_ZOPEFD,log,(char *)Argp);
176 #else
177     vfprintf(PETSC_ZOPEFD,log,Argp);
178 #endif
179     fflush(PETSC_ZOPEFD);
180   }
181   return 0;
182 }
183 
184 #undef __FUNCT__
185 #define __FUNCT__ "PetscVFPrintfDefault"
186 /*@C
187      PetscVFPrintf -  All PETSc standard out and error messages are sent through this function; so, in theory, this can
188         can be replaced with something that does not simply write to a file.
189 
190       To use, write your own function for example,
191 $PetscErrorCode mypetscvfprintf(FILE *fd,const char format[],va_list Argp)
192 ${
193 $  PetscErrorCode ierr;
194 $
195 $  PetscFunctionBegin;
196 $   if (fd != stdout && fd != stderr) {  handle regular files
197 $      ierr = PetscVFPrintfDefault(fd,format,Argp); CHKERR(ierr);
198 $  } else {
199 $     char   buff[BIG];
200 $     size_t length;
201 $     ierr = PetscVSNPrintf(buff,BIG,format,&length,Argp);CHKERRQ(ierr);
202 $     now send buff to whatever stream or whatever you want
203 $ }
204 $ PetscFunctionReturn(0);
205 $}
206 then before the call to PetscInitialize() do the assignment
207 $    PetscVFPrintf = mypetscvfprintf;
208 
209       Notes: For error messages this may be called by any process, for regular standard out it is
210           called only by process 0 of a given communicator
211 
212       Developer Notes: this could be called by an error handler, if that happens then a recursion of the error handler may occur
213                        and a crash
214 
215   Level:  developer
216 
217 .seealso: PetscVSNPrintf(), PetscErrorPrintf()
218 
219 @*/
220 PetscErrorCode  PetscVFPrintfDefault(FILE *fd,const char *format,va_list Argp)
221 {
222   char           *newformat;
223   char           formatbuf[8*1024];
224   size_t         oldLength;
225   PetscErrorCode ierr;
226 
227   PetscFunctionBegin;
228   ierr = PetscStrlen(format, &oldLength);CHKERRQ(ierr);
229   if (oldLength < 8*1024) {
230     newformat = formatbuf;
231     oldLength = 8*1024-1;
232   } else {
233     oldLength = PETSC_MAX_LENGTH_FORMAT(oldLength);
234     ierr = PetscMalloc(oldLength * sizeof(char), &newformat);CHKERRQ(ierr);
235   }
236   ierr = PetscFormatConvert(format,newformat,oldLength);CHKERRQ(ierr);
237 
238 #if defined(PETSC_HAVE_VFPRINTF_CHAR)
239   vfprintf(fd,newformat,(char *)Argp);
240 #else
241   vfprintf(fd,newformat,Argp);
242 #endif
243   fflush(fd);
244   if (oldLength >= 8*1024) {
245     ierr = PetscFree(newformat);CHKERRQ(ierr);
246   }
247   PetscFunctionReturn(0);
248 }
249 
250 #undef __FUNCT__
251 #define __FUNCT__ "PetscSNPrintf"
252 /*@C
253     PetscSNPrintf - Prints to a string of given length
254 
255     Not Collective
256 
257     Input Parameters:
258 +   str - the string to print to
259 .   len - the length of str
260 .   format - the usual printf() format string
261 -   any arguments
262 
263    Level: intermediate
264 
265 .seealso: PetscSynchronizedFlush(), PetscSynchronizedFPrintf(), PetscFPrintf(), PetscVSNPrintf(),
266           PetscPrintf(), PetscViewerASCIIPrintf(), PetscViewerASCIISynchronizedPrintf()
267 @*/
268 PetscErrorCode  PetscSNPrintf(char *str,size_t len,const char format[],...)
269 {
270   PetscErrorCode ierr;
271   size_t         fullLength;
272   va_list        Argp;
273 
274   PetscFunctionBegin;
275   va_start(Argp,format);
276   ierr = PetscVSNPrintf(str,len,format,&fullLength,Argp);CHKERRQ(ierr);
277   PetscFunctionReturn(0);
278 }
279 
280 #undef __FUNCT__
281 #define __FUNCT__ "PetscSNPrintfCount"
282 /*@C
283     PetscSNPrintfCount - Prints to a string of given length, returns count
284 
285     Not Collective
286 
287     Input Parameters:
288 +   str - the string to print to
289 .   len - the length of str
290 .   format - the usual printf() format string
291 .   countused - number of characters used
292 -   any arguments
293 
294    Level: intermediate
295 
296 .seealso: PetscSynchronizedFlush(), PetscSynchronizedFPrintf(), PetscFPrintf(), PetscVSNPrintf(),
297           PetscPrintf(), PetscViewerASCIIPrintf(), PetscViewerASCIISynchronizedPrintf(), PetscSNPrintf()
298 @*/
299 PetscErrorCode  PetscSNPrintfCount(char *str,size_t len,const char format[],size_t *countused,...)
300 {
301   PetscErrorCode ierr;
302   va_list        Argp;
303 
304   PetscFunctionBegin;
305   va_start(Argp,countused);
306   ierr = PetscVSNPrintf(str,len,format,countused,Argp);CHKERRQ(ierr);
307   PetscFunctionReturn(0);
308 }
309 
310 /* ----------------------------------------------------------------------- */
311 
312 PrintfQueue queue       = 0,queuebase = 0;
313 int         queuelength = 0;
314 FILE        *queuefile  = PETSC_NULL;
315 
316 #undef __FUNCT__
317 #define __FUNCT__ "PetscSynchronizedPrintf"
318 /*@C
319     PetscSynchronizedPrintf - Prints synchronized output from several processors.
320     Output of the first processor is followed by that of the second, etc.
321 
322     Not Collective
323 
324     Input Parameters:
325 +   comm - the communicator
326 -   format - the usual printf() format string
327 
328    Level: intermediate
329 
330     Notes:
331     REQUIRES a intervening call to PetscSynchronizedFlush() for the information
332     from all the processors to be printed.
333 
334     Fortran Note:
335     The call sequence is PetscSynchronizedPrintf(MPI_Comm, character(*), PetscErrorCode ierr) from Fortran.
336     That is, you can only pass a single character string from Fortran.
337 
338 .seealso: PetscSynchronizedFlush(), PetscSynchronizedFPrintf(), PetscFPrintf(),
339           PetscPrintf(), PetscViewerASCIIPrintf(), PetscViewerASCIISynchronizedPrintf()
340 @*/
341 PetscErrorCode  PetscSynchronizedPrintf(MPI_Comm comm,const char format[],...)
342 {
343   PetscErrorCode ierr;
344   PetscMPIInt    rank;
345 
346   PetscFunctionBegin;
347   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
348 
349   /* First processor prints immediately to stdout */
350   if (!rank) {
351     va_list Argp;
352     va_start(Argp,format);
353     ierr = (*PetscVFPrintf)(PETSC_STDOUT,format,Argp);CHKERRQ(ierr);
354     if (petsc_history) {
355       va_start(Argp,format);
356       ierr = (*PetscVFPrintf)(petsc_history,format,Argp);CHKERRQ(ierr);
357     }
358     va_end(Argp);
359   } else { /* other processors add to local queue */
360     va_list     Argp;
361     PrintfQueue next;
362     size_t      fullLength = 8191;
363 
364     ierr = PetscNew(struct _PrintfQueue,&next);CHKERRQ(ierr);
365     if (queue) {queue->next = next; queue = next; queue->next = 0;}
366     else       {queuebase   = queue = next;}
367     queuelength++;
368     next->size = -1;
369     while((PetscInt)fullLength >= next->size) {
370       next->size = fullLength+1;
371       ierr = PetscMalloc(next->size * sizeof(char), &next->string);CHKERRQ(ierr);
372       va_start(Argp,format);
373       ierr = PetscMemzero(next->string,next->size);CHKERRQ(ierr);
374       ierr = PetscVSNPrintf(next->string,next->size,format, &fullLength,Argp);CHKERRQ(ierr);
375       va_end(Argp);
376     }
377   }
378 
379   PetscFunctionReturn(0);
380 }
381 
382 #undef __FUNCT__
383 #define __FUNCT__ "PetscSynchronizedFPrintf"
384 /*@C
385     PetscSynchronizedFPrintf - Prints synchronized output to the specified file from
386     several processors.  Output of the first processor is followed by that of the
387     second, etc.
388 
389     Not Collective
390 
391     Input Parameters:
392 +   comm - the communicator
393 .   fd - the file pointer
394 -   format - the usual printf() format string
395 
396     Level: intermediate
397 
398     Notes:
399     REQUIRES a intervening call to PetscSynchronizedFlush() for the information
400     from all the processors to be printed.
401 
402 .seealso: PetscSynchronizedPrintf(), PetscSynchronizedFlush(), PetscFPrintf(),
403           PetscFOpen(), PetscViewerASCIISynchronizedPrintf(), PetscViewerASCIIPrintf()
404 
405 @*/
406 PetscErrorCode  PetscSynchronizedFPrintf(MPI_Comm comm,FILE* fp,const char format[],...)
407 {
408   PetscErrorCode ierr;
409   PetscMPIInt    rank;
410 
411   PetscFunctionBegin;
412   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
413 
414   /* First processor prints immediately to fp */
415   if (!rank) {
416     va_list Argp;
417     va_start(Argp,format);
418     ierr = (*PetscVFPrintf)(fp,format,Argp);CHKERRQ(ierr);
419     queuefile = fp;
420     if (petsc_history && (fp !=petsc_history)) {
421       va_start(Argp,format);
422       ierr = (*PetscVFPrintf)(petsc_history,format,Argp);CHKERRQ(ierr);
423     }
424     va_end(Argp);
425   } else { /* other processors add to local queue */
426     va_list     Argp;
427     PrintfQueue next;
428     size_t      fullLength = 8191;
429     ierr = PetscNew(struct _PrintfQueue,&next);CHKERRQ(ierr);
430     if (queue) {queue->next = next; queue = next; queue->next = 0;}
431     else       {queuebase   = queue = next;}
432     queuelength++;
433     next->size = -1;
434     while((PetscInt)fullLength >= next->size) {
435       next->size = fullLength+1;
436       ierr = PetscMalloc(next->size * sizeof(char), &next->string);CHKERRQ(ierr);
437       va_start(Argp,format);
438       ierr = PetscMemzero(next->string,next->size);CHKERRQ(ierr);
439       ierr = PetscVSNPrintf(next->string,next->size,format,&fullLength,Argp);CHKERRQ(ierr);
440       va_end(Argp);
441     }
442   }
443   PetscFunctionReturn(0);
444 }
445 
446 #undef __FUNCT__
447 #define __FUNCT__ "PetscSynchronizedFlush"
448 /*@
449     PetscSynchronizedFlush - Flushes to the screen output from all processors
450     involved in previous PetscSynchronizedPrintf() calls.
451 
452     Collective on MPI_Comm
453 
454     Input Parameters:
455 .   comm - the communicator
456 
457     Level: intermediate
458 
459     Notes:
460     Usage of PetscSynchronizedPrintf() and PetscSynchronizedFPrintf() with
461     different MPI communicators REQUIRES an intervening call to PetscSynchronizedFlush().
462 
463 .seealso: PetscSynchronizedPrintf(), PetscFPrintf(), PetscPrintf(), PetscViewerASCIIPrintf(),
464           PetscViewerASCIISynchronizedPrintf()
465 @*/
466 PetscErrorCode  PetscSynchronizedFlush(MPI_Comm comm)
467 {
468   PetscErrorCode ierr;
469   PetscMPIInt    rank,size,tag,i,j,n,dummy = 0;
470   char          *message;
471   MPI_Status     status;
472   FILE           *fd;
473 
474   PetscFunctionBegin;
475   ierr = PetscCommDuplicate(comm,&comm,&tag);CHKERRQ(ierr);
476   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
477   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
478 
479   /* First processor waits for messages from all other processors */
480   if (!rank) {
481     if (queuefile) {
482       fd = queuefile;
483     } else {
484       fd = PETSC_STDOUT;
485     }
486     for (i=1; i<size; i++) {
487       /* to prevent a flood of messages to process zero, request each message separately */
488       ierr = MPI_Send(&dummy,1,MPI_INT,i,tag,comm);CHKERRQ(ierr);
489       ierr = MPI_Recv(&n,1,MPI_INT,i,tag,comm,&status);CHKERRQ(ierr);
490       for (j=0; j<n; j++) {
491         PetscMPIInt size;
492 
493         ierr = MPI_Recv(&size,1,MPI_INT,i,tag,comm,&status);CHKERRQ(ierr);
494         ierr = PetscMalloc(size * sizeof(char), &message);CHKERRQ(ierr);
495         ierr = MPI_Recv(message,size,MPI_CHAR,i,tag,comm,&status);CHKERRQ(ierr);
496         ierr = PetscFPrintf(comm,fd,"%s",message);
497         ierr = PetscFree(message);CHKERRQ(ierr);
498       }
499     }
500     queuefile = PETSC_NULL;
501   } else { /* other processors send queue to processor 0 */
502     PrintfQueue next = queuebase,previous;
503 
504     ierr = MPI_Recv(&dummy,1,MPI_INT,0,tag,comm,&status);CHKERRQ(ierr);
505     ierr = MPI_Send(&queuelength,1,MPI_INT,0,tag,comm);CHKERRQ(ierr);
506     for (i=0; i<queuelength; i++) {
507       ierr     = MPI_Send(&next->size,1,MPI_INT,0,tag,comm);CHKERRQ(ierr);
508       ierr     = MPI_Send(next->string,next->size,MPI_CHAR,0,tag,comm);CHKERRQ(ierr);
509       previous = next;
510       next     = next->next;
511       ierr     = PetscFree(previous->string);CHKERRQ(ierr);
512       ierr     = PetscFree(previous);CHKERRQ(ierr);
513     }
514     queue       = 0;
515     queuelength = 0;
516   }
517   ierr = PetscCommDestroy(&comm);CHKERRQ(ierr);
518   PetscFunctionReturn(0);
519 }
520 
521 /* ---------------------------------------------------------------------------------------*/
522 
523 #undef __FUNCT__
524 #define __FUNCT__ "PetscFPrintf"
525 /*@C
526     PetscFPrintf - Prints to a file, only from the first
527     processor in the communicator.
528 
529     Not Collective
530 
531     Input Parameters:
532 +   comm - the communicator
533 .   fd - the file pointer
534 -   format - the usual printf() format string
535 
536     Level: intermediate
537 
538     Fortran Note:
539     This routine is not supported in Fortran.
540 
541    Concepts: printing^in parallel
542    Concepts: printf^in parallel
543 
544 .seealso: PetscPrintf(), PetscSynchronizedPrintf(), PetscViewerASCIIPrintf(),
545           PetscViewerASCIISynchronizedPrintf(), PetscSynchronizedFlush()
546 @*/
547 PetscErrorCode  PetscFPrintf(MPI_Comm comm,FILE* fd,const char format[],...)
548 {
549   PetscErrorCode ierr;
550   PetscMPIInt    rank;
551 
552   PetscFunctionBegin;
553   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
554   if (!rank) {
555     va_list Argp;
556     va_start(Argp,format);
557     ierr = (*PetscVFPrintf)(fd,format,Argp);CHKERRQ(ierr);
558     if (petsc_history && (fd !=petsc_history)) {
559       va_start(Argp,format);
560       ierr = (*PetscVFPrintf)(petsc_history,format,Argp);CHKERRQ(ierr);
561       }
562     va_end(Argp);
563   }
564   PetscFunctionReturn(0);
565 }
566 
567 #undef __FUNCT__
568 #define __FUNCT__ "PetscPrintf"
569 /*@C
570     PetscPrintf - Prints to standard out, only from the first
571     processor in the communicator. Calls from other processes are ignored.
572 
573     Not Collective
574 
575     Input Parameters:
576 +   comm - the communicator
577 -   format - the usual printf() format string
578 
579    Level: intermediate
580 
581     Fortran Note:
582     The call sequence is PetscPrintf(MPI_Comm, character(*), PetscErrorCode ierr) from Fortran.
583     That is, you can only pass a single character string from Fortran.
584 
585    Concepts: printing^in parallel
586    Concepts: printf^in parallel
587 
588 .seealso: PetscFPrintf(), PetscSynchronizedPrintf()
589 @*/
590 PetscErrorCode  PetscPrintf(MPI_Comm comm,const char format[],...)
591 {
592   PetscErrorCode ierr;
593   PetscMPIInt    rank;
594 
595   PetscFunctionBegin;
596   if (!comm) comm = PETSC_COMM_WORLD;
597   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
598   if (!rank) {
599     va_list Argp;
600     va_start(Argp,format);
601     ierr = (*PetscVFPrintf)(PETSC_STDOUT,format,Argp);CHKERRQ(ierr);
602     if (petsc_history) {
603       va_start(Argp,format);
604       ierr = (*PetscVFPrintf)(petsc_history,format,Argp);CHKERRQ(ierr);
605     }
606     va_end(Argp);
607   }
608   PetscFunctionReturn(0);
609 }
610 
611 /* ---------------------------------------------------------------------------------------*/
612 #undef __FUNCT__
613 #define __FUNCT__ "PetscHelpPrintfDefault"
614 /*@C
615      PetscHelpPrintf -  All PETSc help messages are passing through this function. You can change how help messages are printed by
616         replacinng it  with something that does not simply write to a stdout.
617 
618       To use, write your own function for example,
619 $PetscErrorCode mypetschelpprintf(MPI_Comm comm,const char format[],....)
620 ${
621 $ PetscFunctionReturn(0);
622 $}
623 then before the call to PetscInitialize() do the assignment
624 $    PetscHelpPrintf = mypetschelpprintf;
625 
626   Note: the default routine used is called PetscHelpPrintfDefault().
627 
628   Level:  developer
629 
630 .seealso: PetscVSNPrintf(), PetscVFPrintf(), PetscErrorPrintf()
631 @*/
632 PetscErrorCode  PetscHelpPrintfDefault(MPI_Comm comm,const char format[],...)
633 {
634   PetscErrorCode ierr;
635   PetscMPIInt    rank;
636 
637   PetscFunctionBegin;
638   if (!comm) comm = PETSC_COMM_WORLD;
639   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
640   if (!rank) {
641     va_list Argp;
642     va_start(Argp,format);
643     ierr = (*PetscVFPrintf)(PETSC_STDOUT,format,Argp);CHKERRQ(ierr);
644     if (petsc_history) {
645       va_start(Argp,format);
646       ierr = (*PetscVFPrintf)(petsc_history,format,Argp);CHKERRQ(ierr);
647     }
648     va_end(Argp);
649   }
650   PetscFunctionReturn(0);
651 }
652 
653 /* ---------------------------------------------------------------------------------------*/
654 
655 
656 #undef __FUNCT__
657 #define __FUNCT__ "PetscSynchronizedFGets"
658 /*@C
659     PetscSynchronizedFGets - Several processors all get the same line from a file.
660 
661     Collective on MPI_Comm
662 
663     Input Parameters:
664 +   comm - the communicator
665 .   fd - the file pointer
666 -   len - the length of the output buffer
667 
668     Output Parameter:
669 .   string - the line read from the file
670 
671     Level: intermediate
672 
673 .seealso: PetscSynchronizedPrintf(), PetscSynchronizedFlush(),
674           PetscFOpen(), PetscViewerASCIISynchronizedPrintf(), PetscViewerASCIIPrintf()
675 
676 @*/
677 PetscErrorCode  PetscSynchronizedFGets(MPI_Comm comm,FILE* fp,size_t len,char string[])
678 {
679   PetscErrorCode ierr;
680   PetscMPIInt    rank;
681 
682   PetscFunctionBegin;
683   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
684 
685   if (!rank) {
686     char *ptr = fgets(string, len, fp);
687 
688     if (!ptr) {
689       if (feof(fp)) {
690         len = 0;
691       } else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from file: %d", errno);
692     }
693   }
694   ierr = MPI_Bcast(string,len,MPI_BYTE,0,comm);CHKERRQ(ierr);
695   PetscFunctionReturn(0);
696 }
697 
698 #if defined(PETSC_HAVE_MATLAB_ENGINE)
699 #include <mex.h>
700 #undef __FUNCT__
701 #define __FUNCT__ "PetscVFPrintf_Matlab"
702 PetscErrorCode  PetscVFPrintf_Matlab(FILE *fd,const char format[],va_list Argp)
703 {
704   PetscErrorCode ierr;
705 
706   PetscFunctionBegin;
707   if (fd != stdout && fd != stderr) { /* handle regular files */
708     ierr = PetscVFPrintfDefault(fd,format,Argp); CHKERRQ(ierr);
709   } else {
710     size_t len=8*1024,length;
711     char   buf[len];
712 
713     ierr = PetscVSNPrintf(buf,len,format,&length,Argp);CHKERRQ(ierr);
714     mexPrintf("%s",buf);
715  }
716  PetscFunctionReturn(0);
717 }
718 #endif
719 
720 #undef __FUNCT__
721 #define __FUNCT__ "PetscFormatStrip"
722 /*@C
723      PetscFormatStrip - Takes a PETSc format string and removes all numerical modifiers to % operations
724 
725    Input Parameters:
726 .   format - the PETSc format string
727 
728  Level: developer
729 
730 @*/
731 PetscErrorCode  PetscFormatStrip(char *format)
732 {
733   size_t   loc1 = 0, loc2 = 0;
734 
735   PetscFunctionBegin;
736   while (format[loc2]){
737     if (format[loc2] == '%') {
738       format[loc1++] = format[loc2++];
739       while (format[loc2] && ((format[loc2] >= '0' && format[loc2] <= '9') || format[loc2] == '.')) loc2++;
740     }
741     format[loc1++] = format[loc2++];
742   }
743   PetscFunctionReturn(0);
744 }
745 
746 static PetscToken OriginalRun = 0;
747 
748 #undef __FUNCT__
749 #define __FUNCT__ "PetscVFPrintfRegressDestroy"
750 static PetscErrorCode PetscVFPrintfRegressDestroy(void)
751 {
752   PetscErrorCode ierr;
753 
754   PetscFunctionBegin;
755   ierr = PetscTokenDestroy(&OriginalRun);CHKERRQ(ierr);
756   PetscFunctionReturn(0);
757 }
758 
759 #undef __FUNCT__
760 #define __FUNCT__ "PetscVFPrintfRegressSetUp"
761 /*@C
762      PetscVFPrintfRegressSetUp -  Reads in file of previous results of run to compare with current run using PetscVFPrintfRegress
763 
764   Level:  developer
765 
766 .seealso: PetscVSNPrintf(), PetscErrorPrintf(), PetscVFPrintfRegress()
767 
768 @*/
769 PetscErrorCode  PetscVFPrintfRegressSetUp(MPI_Comm comm,const char *filename)
770 {
771   PetscErrorCode ierr;
772   FILE           *fp;
773   char           buffer[1024],*big;
774   size_t         cnt = 0,len;
775   char           *ptr;
776   PetscMPIInt    rank;
777 
778   PetscFunctionBegin;
779   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
780   if (!rank) {
781     ierr = PetscFOpen(comm,filename,"r",&fp);CHKERRQ(ierr);
782 
783     ptr = fgets(buffer, 1024, fp);
784     while (ptr) {
785       ierr = PetscStrlen(ptr,&len);CHKERRQ(ierr);
786       cnt  += len;
787       ptr = fgets(buffer, 1024, fp);
788     }
789     if (!feof(fp)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from file: %d", errno);
790     ierr = PetscFClose(comm,fp);CHKERRQ(ierr);
791     ierr = PetscMalloc(cnt*sizeof(char),&big);CHKERRQ(ierr);
792     big[0] = 0;
793     ierr = PetscFOpen(comm,filename,"r",&fp);CHKERRQ(ierr);
794     ptr = fgets(buffer, 1024, fp);
795     while (ptr) {
796       ierr = PetscStrcat(big,ptr);CHKERRQ(ierr);
797       ptr = fgets(buffer, 1024, fp);
798     }
799     if (!feof(fp)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from file: %d", errno);
800     ierr = PetscFClose(comm,fp);CHKERRQ(ierr);
801     ierr = PetscTokenCreate(big,'\n',&OriginalRun);CHKERRQ(ierr);
802     ierr = PetscFree(big);CHKERRQ(ierr);
803     PetscVFPrintf = PetscVFPrintfRegress;
804     ierr = PetscRegisterFinalize(PetscVFPrintfRegressDestroy);CHKERRQ(ierr);
805   }
806   PetscFunctionReturn(0);
807 }
808 
809 
810 #undef __FUNCT__
811 #define __FUNCT__ "PetscVFPrintfRegress"
812 /*@C
813      PetscVFPrintfRegress -  Special version of PetscVFPrintf() to help make clean PETSc regression tests
814 
815   Level:  developer
816 
817   Developer Notes:
818        Since this routine knows exactly the data-types and formats of each of the arguments it could in theory do an appropriate
819        diff for each argument, rather than using a string diff on the entire result.
820 
821        So we should somehow loop over all the parts of the format string check that the string part matches and the arguments match
822        within a reasonable tolerance.
823 
824 .seealso: PetscVSNPrintf(), PetscErrorPrintf()
825 
826 @*/
827 PetscErrorCode  PetscVFPrintfRegress(FILE *fd,const char *format,va_list Argp)
828 {
829   char              *newformat,*nformat,*oresult;
830   char              formatbuf[8*1024],testbuf[8*1024];
831   size_t            oldLength;
832   PetscErrorCode    ierr;
833   char              *result;
834   PetscBool         same;
835   size_t            len;
836   int               found;
837   va_list           cArgp;
838 
839   PetscFunctionBegin;
840   va_copy(cArgp,Argp);
841   ierr = PetscTokenFind(OriginalRun,&result);CHKERRQ(ierr);
842   if (!result) {
843     printf("Fewer lines in original, than in regression test\n");
844     exit(0);
845   }
846 
847   ierr = PetscStrlen(format, &oldLength);CHKERRQ(ierr);
848   if (oldLength < 8*1024) {
849     newformat = formatbuf;
850     oldLength = 8*1024-1;
851   } else {
852     oldLength = PETSC_MAX_LENGTH_FORMAT(oldLength);
853     ierr = PetscMalloc(oldLength * sizeof(char), &newformat);CHKERRQ(ierr);
854   }
855   ierr = PetscFormatConvert(format,newformat,oldLength);CHKERRQ(ierr);
856   ierr = PetscVSNPrintf(testbuf,8*1024,newformat,&len,Argp);CHKERRQ(ierr);
857   testbuf[len-1] = 0; /* remove \n at end of line */
858   ierr = PetscStrcmp(result,testbuf,&same);CHKERRQ(ierr);
859   if (!same) {
860     char *sub;
861     same = PETSC_TRUE;
862     ierr = PetscFormatStrip(newformat);CHKERRQ(ierr);
863     nformat = newformat;
864     oresult = result;
865 
866     ierr = PetscStrstr(nformat,"%",&sub);CHKERRQ(ierr);
867     while (sub) {
868       sub++;
869       if (*sub == 'g' || *sub == 'f') {
870         float  val;
871         double nval;
872         char   tsub = sub[1];
873         sub++; *sub = 0;
874         found = sscanf(oresult,nformat,&val);
875         if (!found) {
876           printf("Old::%s\nNew::%s\n",result,testbuf);
877           printf("Different because not scan:%s: from :%s:\n",nformat,oresult);
878           same = PETSC_FALSE;
879           break;
880         }
881         nval = va_arg(cArgp,double);
882         if (PetscAbs((nval - val)/(nval + val)) > .1) {
883           printf("Old::%s\nNew::%s\n",result,testbuf);
884           printf("Different because float values %g to far from %g\n",val,nval);
885           same = PETSC_FALSE;
886           break;
887         }
888         *sub = tsub;
889         while (*nformat == *oresult) {nformat++; oresult++;}
890         while (*oresult == ' ') oresult++;
891         while ((*oresult >= '0' && *oresult <= '9') || *oresult == '.' || *oresult == '-' || *oresult == 'e') oresult++;
892       } else if (*sub == 'd') {
893         int   val,nval;
894         char  tsub = sub[1];
895         sub++; *sub = 0;
896         found = sscanf(oresult,nformat,&val);
897         if (!found) {
898           printf("Old::%s\nNew::%s\n",result,testbuf);
899           printf("Different because not scan:%s: from :%s:\n",nformat,oresult);
900           same = PETSC_FALSE;
901           break;
902         }
903         nval = va_arg(cArgp,int);
904         if (val != nval) {
905           printf("Old::%s\nNew::%s\n",result,testbuf);
906           printf("Different because integer value %d != %d\n",val,nval);
907           same = PETSC_FALSE;
908           break;
909         }
910         *sub = tsub;
911         while (*nformat == *oresult) {nformat++; oresult++;}
912         while (*oresult == ' ') oresult++;
913         while ((*oresult >= '0' && *oresult <= '9') || *oresult == '-') oresult++;
914       }
915       nformat = sub;
916       ierr = PetscStrstr(nformat,"%",&sub);CHKERRQ(ierr);
917     }
918   }
919 
920   if (oldLength >= 8*1024) {
921     ierr = PetscFree(newformat);CHKERRQ(ierr);
922   }
923   PetscFunctionReturn(0);
924 }
925