xref: /petsc/src/sys/classes/viewer/impls/ascii/filev.c (revision 1511cd715a1f0c8d257549c5ebe5cee9c6feed4d)
1 
2 #include <../src/sys/classes/viewer/impls/ascii/asciiimpl.h> /*I "petscviewer.h" I*/
3 
4 #define QUEUESTRINGSIZE 8192
5 
6 static PetscErrorCode PetscViewerFileClose_ASCII(PetscViewer viewer) {
7   PetscMPIInt        rank;
8   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
9   int                err;
10 
11   PetscFunctionBegin;
12   PetscCheck(!vascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
13   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
14   if (rank == 0 && vascii->fd != stderr && vascii->fd != PETSC_STDOUT) {
15     if (vascii->fd && vascii->closefile) {
16       err = fclose(vascii->fd);
17       PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file");
18     }
19     if (vascii->storecompressed) {
20       char  par[PETSC_MAX_PATH_LEN], buf[PETSC_MAX_PATH_LEN];
21       FILE *fp;
22       PetscCall(PetscStrncpy(par, "gzip ", sizeof(par)));
23       PetscCall(PetscStrlcat(par, vascii->filename, sizeof(par)));
24 #if defined(PETSC_HAVE_POPEN)
25       PetscCall(PetscPOpen(PETSC_COMM_SELF, NULL, par, "r", &fp));
26       PetscCheck(!fgets(buf, 1024, fp), PETSC_COMM_SELF, PETSC_ERR_LIB, "Error from compression command %s\n%s", par, buf);
27       PetscCall(PetscPClose(PETSC_COMM_SELF, fp));
28 #else
29       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot run external programs on this machine");
30 #endif
31     }
32   }
33   PetscCall(PetscFree(vascii->filename));
34   PetscFunctionReturn(0);
35 }
36 
37 /* ----------------------------------------------------------------------*/
38 PetscErrorCode PetscViewerDestroy_ASCII(PetscViewer viewer) {
39   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
40   PetscViewerLink   *vlink;
41   PetscBool          flg;
42 
43   PetscFunctionBegin;
44   PetscCheck(!vascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
45   PetscCall(PetscViewerFileClose_ASCII(viewer));
46   PetscCall(PetscFree(vascii));
47 
48   /* remove the viewer from the list in the MPI Communicator */
49   if (Petsc_Viewer_keyval == MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, Petsc_DelViewer, &Petsc_Viewer_keyval, (void *)0));
50 
51   PetscCallMPI(MPI_Comm_get_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_keyval, (void **)&vlink, (PetscMPIInt *)&flg));
52   if (flg) {
53     if (vlink && vlink->viewer == viewer) {
54       if (vlink->next) {
55         PetscCallMPI(MPI_Comm_set_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_keyval, vlink->next));
56       } else {
57         PetscCallMPI(MPI_Comm_delete_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_keyval));
58       }
59       PetscCall(PetscFree(vlink));
60     } else {
61       while (vlink && vlink->next) {
62         if (vlink->next->viewer == viewer) {
63           PetscViewerLink *nv = vlink->next;
64           vlink->next         = vlink->next->next;
65           PetscCall(PetscFree(nv));
66         }
67         vlink = vlink->next;
68       }
69     }
70   }
71 
72   if (Petsc_Viewer_Stdout_keyval != MPI_KEYVAL_INVALID) {
73     PetscViewer aviewer;
74     PetscCallMPI(MPI_Comm_get_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_Stdout_keyval, (void **)&aviewer, (PetscMPIInt *)&flg));
75     if (flg && aviewer == viewer) PetscCallMPI(MPI_Comm_delete_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_Stdout_keyval));
76   }
77   if (Petsc_Viewer_Stderr_keyval != MPI_KEYVAL_INVALID) {
78     PetscViewer aviewer;
79     PetscCallMPI(MPI_Comm_get_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_Stderr_keyval, (void **)&aviewer, (PetscMPIInt *)&flg));
80     if (flg && aviewer == viewer) PetscCallMPI(MPI_Comm_delete_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_Stderr_keyval));
81   }
82   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", NULL));
83   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetName_C", NULL));
84   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", NULL));
85   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetMode_C", NULL));
86   PetscFunctionReturn(0);
87 }
88 
89 PetscErrorCode PetscViewerDestroy_ASCII_SubViewer(PetscViewer viewer) {
90   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
91 
92   PetscFunctionBegin;
93   PetscCall(PetscViewerRestoreSubViewer(vascii->bviewer, 0, &viewer));
94   PetscFunctionReturn(0);
95 }
96 
97 PetscErrorCode PetscViewerFlush_ASCII(PetscViewer viewer) {
98   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
99   int                err;
100   MPI_Comm           comm;
101   PetscMPIInt        rank, size;
102   FILE              *fd = vascii->fd;
103 
104   PetscFunctionBegin;
105   PetscCheck(!vascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
106   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
107   PetscCallMPI(MPI_Comm_rank(comm, &rank));
108   PetscCallMPI(MPI_Comm_size(comm, &size));
109 
110   if (!vascii->bviewer && rank == 0 && (vascii->mode != FILE_MODE_READ)) {
111     err = fflush(vascii->fd);
112     PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fflush() call failed");
113   }
114 
115   if (vascii->allowsynchronized) {
116     PetscMPIInt tag, i, j, n = 0, dummy = 0;
117     char       *message;
118     MPI_Status  status;
119 
120     PetscCall(PetscCommDuplicate(comm, &comm, &tag));
121 
122     /* First processor waits for messages from all other processors */
123     if (rank == 0) {
124       /* flush my own messages that I may have queued up */
125       PrintfQueue next = vascii->petsc_printfqueuebase, previous;
126       for (i = 0; i < vascii->petsc_printfqueuelength; i++) {
127         if (!vascii->bviewer) {
128           PetscCall(PetscFPrintf(comm, fd, "%s", next->string));
129         } else {
130           PetscCall(PetscViewerASCIISynchronizedPrintf(vascii->bviewer, "%s", next->string));
131         }
132         previous = next;
133         next     = next->next;
134         PetscCall(PetscFree(previous->string));
135         PetscCall(PetscFree(previous));
136       }
137       vascii->petsc_printfqueue       = NULL;
138       vascii->petsc_printfqueuelength = 0;
139       for (i = 1; i < size; i++) {
140         /* to prevent a flood of messages to process zero, request each message separately */
141         PetscCallMPI(MPI_Send(&dummy, 1, MPI_INT, i, tag, comm));
142         PetscCallMPI(MPI_Recv(&n, 1, MPI_INT, i, tag, comm, &status));
143         for (j = 0; j < n; j++) {
144           PetscMPIInt size = 0;
145 
146           PetscCallMPI(MPI_Recv(&size, 1, MPI_INT, i, tag, comm, &status));
147           PetscCall(PetscMalloc1(size, &message));
148           PetscCallMPI(MPI_Recv(message, size, MPI_CHAR, i, tag, comm, &status));
149           if (!vascii->bviewer) {
150             PetscCall(PetscFPrintf(comm, fd, "%s", message));
151           } else {
152             PetscCall(PetscViewerASCIISynchronizedPrintf(vascii->bviewer, "%s", message));
153           }
154           PetscCall(PetscFree(message));
155         }
156       }
157     } else { /* other processors send queue to processor 0 */
158       PrintfQueue next = vascii->petsc_printfqueuebase, previous;
159 
160       PetscCallMPI(MPI_Recv(&dummy, 1, MPI_INT, 0, tag, comm, &status));
161       PetscCallMPI(MPI_Send(&vascii->petsc_printfqueuelength, 1, MPI_INT, 0, tag, comm));
162       for (i = 0; i < vascii->petsc_printfqueuelength; i++) {
163         PetscCallMPI(MPI_Send(&next->size, 1, MPI_INT, 0, tag, comm));
164         PetscCallMPI(MPI_Send(next->string, next->size, MPI_CHAR, 0, tag, comm));
165         previous = next;
166         next     = next->next;
167         PetscCall(PetscFree(previous->string));
168         PetscCall(PetscFree(previous));
169       }
170       vascii->petsc_printfqueue       = NULL;
171       vascii->petsc_printfqueuelength = 0;
172     }
173     PetscCall(PetscCommDestroy(&comm));
174   }
175   PetscFunctionReturn(0);
176 }
177 
178 /*@C
179     PetscViewerASCIIGetPointer - Extracts the file pointer from an ASCII PetscViewer.
180 
181     Not Collective, depending on the viewer the value may be meaningless except for process 0 of the viewer
182 
183     Input Parameter:
184 .    viewer - PetscViewer context, obtained from PetscViewerASCIIOpen()
185 
186     Output Parameter:
187 .    fd - file pointer
188 
189     Notes: for the standard PETSCVIEWERASCII the value is valid only on process 0 of the viewer
190 
191     Level: intermediate
192 
193     Fortran Note:
194     This routine is not supported in Fortran.
195 
196 .seealso: `PetscViewerASCIIOpen()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerCreate()`, `PetscViewerASCIIPrintf()`,
197           `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerFlush()`
198 @*/
199 PetscErrorCode PetscViewerASCIIGetPointer(PetscViewer viewer, FILE **fd) {
200   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
201 
202   PetscFunctionBegin;
203   *fd = vascii->fd;
204   PetscFunctionReturn(0);
205 }
206 
207 PetscErrorCode PetscViewerFileGetMode_ASCII(PetscViewer viewer, PetscFileMode *mode) {
208   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
209 
210   PetscFunctionBegin;
211   *mode = vascii->mode;
212   PetscFunctionReturn(0);
213 }
214 
215 PetscErrorCode PetscViewerFileSetMode_ASCII(PetscViewer viewer, PetscFileMode mode) {
216   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
217 
218   PetscFunctionBegin;
219   vascii->mode = mode;
220   PetscFunctionReturn(0);
221 }
222 
223 /*
224    If petsc_history is on, then all Petsc*Printf() results are saved
225    if the appropriate (usually .petschistory) file.
226 */
227 PETSC_INTERN FILE *petsc_history;
228 
229 /*@
230     PetscViewerASCIISetTab - Causes PetscViewer to tab in a number of times
231 
232     Not Collective, but only first processor in set has any effect
233 
234     Input Parameters:
235 +    viewer - obtained with PetscViewerASCIIOpen()
236 -    tabs - number of tabs
237 
238     Level: developer
239 
240     Fortran Note:
241     This routine is not supported in Fortran.
242 
243 .seealso: `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIIGetTab()`,
244           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
245           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPushTab()`
246 @*/
247 PetscErrorCode PetscViewerASCIISetTab(PetscViewer viewer, PetscInt tabs) {
248   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
249   PetscBool          iascii;
250 
251   PetscFunctionBegin;
252   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
253   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
254   if (iascii) ascii->tab = tabs;
255   PetscFunctionReturn(0);
256 }
257 
258 /*@
259     PetscViewerASCIIGetTab - Return the number of tabs used by PetscViewer.
260 
261     Not Collective, meaningful on first processor only.
262 
263     Input Parameters:
264 .    viewer - obtained with PetscViewerASCIIOpen()
265 
266     Output Parameters:
267 .    tabs - number of tabs
268 
269     Level: developer
270 
271     Fortran Note:
272     This routine is not supported in Fortran.
273 
274 .seealso: `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIISetTab()`,
275           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
276           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPushTab()`
277 @*/
278 PetscErrorCode PetscViewerASCIIGetTab(PetscViewer viewer, PetscInt *tabs) {
279   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
280   PetscBool          iascii;
281 
282   PetscFunctionBegin;
283   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
284   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
285   if (iascii && tabs) *tabs = ascii->tab;
286   PetscFunctionReturn(0);
287 }
288 
289 /*@
290     PetscViewerASCIIAddTab - Add to the number of times an ASCII viewer tabs before printing
291 
292     Not Collective, but only first processor in set has any effect
293 
294     Input Parameters:
295 +    viewer - obtained with PetscViewerASCIIOpen()
296 -    tabs - number of tabs
297 
298     Level: developer
299 
300     Fortran Note:
301     This routine is not supported in Fortran.
302 
303 .seealso: `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
304           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
305           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPushTab()`
306 @*/
307 PetscErrorCode PetscViewerASCIIAddTab(PetscViewer viewer, PetscInt tabs) {
308   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
309   PetscBool          iascii;
310 
311   PetscFunctionBegin;
312   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
313   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
314   if (iascii) ascii->tab += tabs;
315   PetscFunctionReturn(0);
316 }
317 
318 /*@
319     PetscViewerASCIISubtractTab - Subtracts from the number of times an ASCII viewer tabs before printing
320 
321     Not Collective, but only first processor in set has any effect
322 
323     Input Parameters:
324 +    viewer - obtained with PetscViewerASCIIOpen()
325 -    tabs - number of tabs
326 
327     Level: developer
328 
329     Fortran Note:
330     This routine is not supported in Fortran.
331 
332 .seealso: `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
333           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
334           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPushTab()`
335 @*/
336 PetscErrorCode PetscViewerASCIISubtractTab(PetscViewer viewer, PetscInt tabs) {
337   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
338   PetscBool          iascii;
339 
340   PetscFunctionBegin;
341   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
342   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
343   if (iascii) ascii->tab -= tabs;
344   PetscFunctionReturn(0);
345 }
346 
347 /*@C
348     PetscViewerASCIIPushSynchronized - Allows calls to PetscViewerASCIISynchronizedPrintf() for this viewer
349 
350     Collective on PetscViewer
351 
352     Input Parameters:
353 .    viewer - obtained with PetscViewerASCIIOpen()
354 
355     Level: intermediate
356 
357     Notes:
358     See documentation of PetscViewerASCIISynchronizedPrintf() for more details how the synchronized output should be done properly.
359 
360 .seealso: `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerFlush()`, `PetscViewerASCIIPopSynchronized()`,
361           `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIIOpen()`,
362           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`
363 @*/
364 PetscErrorCode PetscViewerASCIIPushSynchronized(PetscViewer viewer) {
365   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
366   PetscBool          iascii;
367 
368   PetscFunctionBegin;
369   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
370   PetscCheck(!ascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
371   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
372   if (iascii) ascii->allowsynchronized++;
373   PetscFunctionReturn(0);
374 }
375 
376 /*@C
377     PetscViewerASCIIPopSynchronized - Undoes most recent PetscViewerASCIIPushSynchronized() for this viewer
378 
379     Collective on PetscViewer
380 
381     Input Parameters:
382 .    viewer - obtained with PetscViewerASCIIOpen()
383 
384     Level: intermediate
385 
386     Notes:
387     See documentation of PetscViewerASCIISynchronizedPrintf() for more details how the synchronized output should be done properly.
388 
389 .seealso: `PetscViewerASCIIPushSynchronized()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerFlush()`,
390           `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIIOpen()`,
391           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`
392 @*/
393 PetscErrorCode PetscViewerASCIIPopSynchronized(PetscViewer viewer) {
394   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
395   PetscBool          iascii;
396 
397   PetscFunctionBegin;
398   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
399   PetscCheck(!ascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
400   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
401   if (iascii) {
402     ascii->allowsynchronized--;
403     PetscCheck(ascii->allowsynchronized >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Called more times than PetscViewerASCIIPushSynchronized()");
404   }
405   PetscFunctionReturn(0);
406 }
407 
408 /*@C
409     PetscViewerASCIIPushTab - Adds one more tab to the amount that PetscViewerASCIIPrintf()
410      lines are tabbed.
411 
412     Not Collective, but only first processor in set has any effect
413 
414     Input Parameters:
415 .    viewer - obtained with PetscViewerASCIIOpen()
416 
417     Level: developer
418 
419     Fortran Note:
420     This routine is not supported in Fortran.
421 
422 .seealso: `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
423           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
424           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`
425 @*/
426 PetscErrorCode PetscViewerASCIIPushTab(PetscViewer viewer) {
427   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
428   PetscBool          iascii;
429 
430   PetscFunctionBegin;
431   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
432   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
433   if (iascii) ascii->tab++;
434   PetscFunctionReturn(0);
435 }
436 
437 /*@C
438     PetscViewerASCIIPopTab - Removes one tab from the amount that PetscViewerASCIIPrintf()
439      lines are tabbed.
440 
441     Not Collective, but only first processor in set has any effect
442 
443     Input Parameters:
444 .    viewer - obtained with PetscViewerASCIIOpen()
445 
446     Level: developer
447 
448     Fortran Note:
449     This routine is not supported in Fortran.
450 
451 .seealso: `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
452           `PetscViewerASCIIPushTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
453           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`
454 @*/
455 PetscErrorCode PetscViewerASCIIPopTab(PetscViewer viewer) {
456   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
457   PetscBool          iascii;
458 
459   PetscFunctionBegin;
460   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
461   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
462   if (iascii) {
463     PetscCheck(ascii->tab > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "More tabs popped than pushed");
464     ascii->tab--;
465   }
466   PetscFunctionReturn(0);
467 }
468 
469 /*@
470     PetscViewerASCIIUseTabs - Turns on or off the use of tabs with the ASCII PetscViewer
471 
472     Not Collective, but only first processor in set has any effect
473 
474     Input Parameters:
475 +    viewer - obtained with PetscViewerASCIIOpen()
476 -    flg - PETSC_TRUE or PETSC_FALSE
477 
478     Level: developer
479 
480     Fortran Note:
481     This routine is not supported in Fortran.
482 
483 .seealso: `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
484           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIPushTab()`, `PetscViewerASCIIOpen()`,
485           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`
486 @*/
487 PetscErrorCode PetscViewerASCIIUseTabs(PetscViewer viewer, PetscBool flg) {
488   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
489   PetscBool          iascii;
490 
491   PetscFunctionBegin;
492   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
493   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
494   if (iascii) {
495     if (flg) ascii->tab = ascii->tab_store;
496     else {
497       ascii->tab_store = ascii->tab;
498       ascii->tab       = 0;
499     }
500   }
501   PetscFunctionReturn(0);
502 }
503 
504 /* ----------------------------------------------------------------------- */
505 
506 /*@C
507     PetscViewerASCIIPrintf - Prints to a file, only from the first
508     processor in the PetscViewer
509 
510     Not Collective, but only first processor in set has any effect
511 
512     Input Parameters:
513 +    viewer - obtained with PetscViewerASCIIOpen()
514 -    format - the usual printf() format string
515 
516     Level: developer
517 
518     Fortran Note:
519     The call sequence is PetscViewerASCIIPrintf(PetscViewer, character(*), int ierr) from Fortran.
520     That is, you can only pass a single character string from Fortran.
521 
522 .seealso: `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
523           `PetscViewerASCIIPushTab()`, `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`,
524           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPushSynchronized()`
525 @*/
526 PetscErrorCode PetscViewerASCIIPrintf(PetscViewer viewer, const char format[], ...) {
527   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
528   PetscMPIInt        rank;
529   PetscInt           tab, intab = ascii->tab;
530   FILE              *fd = ascii->fd;
531   PetscBool          iascii;
532   int                err;
533 
534   PetscFunctionBegin;
535   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
536   PetscCheck(!ascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
537   PetscValidCharPointer(format, 2);
538   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
539   PetscCheck(iascii, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not ASCII PetscViewer");
540   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
541   if (rank) PetscFunctionReturn(0);
542 
543   if (ascii->bviewer) { /* pass string up to parent viewer */
544     char   *string;
545     va_list Argp;
546     size_t  fullLength;
547 
548     PetscCall(PetscCalloc1(QUEUESTRINGSIZE, &string));
549     va_start(Argp, format);
550     PetscCall(PetscVSNPrintf(string, QUEUESTRINGSIZE, format, &fullLength, Argp));
551     va_end(Argp);
552     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%s", string));
553     PetscCall(PetscFree(string));
554   } else { /* write directly to file */
555     va_list     Argp;
556     /* flush my own messages that I may have queued up */
557     PrintfQueue next = ascii->petsc_printfqueuebase, previous;
558     PetscInt    i;
559     for (i = 0; i < ascii->petsc_printfqueuelength; i++) {
560       PetscCall(PetscFPrintf(PETSC_COMM_SELF, fd, "%s", next->string));
561       previous = next;
562       next     = next->next;
563       PetscCall(PetscFree(previous->string));
564       PetscCall(PetscFree(previous));
565     }
566     ascii->petsc_printfqueue       = NULL;
567     ascii->petsc_printfqueuelength = 0;
568     tab                            = intab;
569     while (tab--) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fd, "  "));
570 
571     va_start(Argp, format);
572     PetscCall((*PetscVFPrintf)(fd, format, Argp));
573     err = fflush(fd);
574     PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fflush() failed on file");
575     if (petsc_history) {
576       va_start(Argp, format);
577       tab = intab;
578       while (tab--) PetscCall(PetscFPrintf(PETSC_COMM_SELF, petsc_history, "  "));
579       PetscCall((*PetscVFPrintf)(petsc_history, format, Argp));
580       err = fflush(petsc_history);
581       PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fflush() failed on file");
582     }
583     va_end(Argp);
584   }
585   PetscFunctionReturn(0);
586 }
587 
588 /*@C
589      PetscViewerFileSetName - Sets the name of the file the PetscViewer uses.
590 
591     Collective on PetscViewer
592 
593   Input Parameters:
594 +  viewer - the PetscViewer; either ASCII or binary
595 -  name - the name of the file it should use
596 
597     Level: advanced
598 
599 .seealso: `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PetscViewerDestroy()`,
600           `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIISynchronizedPrintf()`
601 
602 @*/
603 PetscErrorCode PetscViewerFileSetName(PetscViewer viewer, const char name[]) {
604   char filename[PETSC_MAX_PATH_LEN];
605 
606   PetscFunctionBegin;
607   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
608   PetscValidCharPointer(name, 2);
609   PetscCall(PetscStrreplace(PetscObjectComm((PetscObject)viewer), name, filename, sizeof(filename)));
610   PetscTryMethod(viewer, "PetscViewerFileSetName_C", (PetscViewer, const char[]), (viewer, filename));
611   PetscFunctionReturn(0);
612 }
613 
614 /*@C
615      PetscViewerFileGetName - Gets the name of the file the PetscViewer uses.
616 
617     Not Collective
618 
619   Input Parameter:
620 .  viewer - the PetscViewer; either ASCII or binary
621 
622   Output Parameter:
623 .  name - the name of the file it is using
624 
625     Level: advanced
626 
627 .seealso: `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PetscViewerFileSetName()`
628 
629 @*/
630 PetscErrorCode PetscViewerFileGetName(PetscViewer viewer, const char **name) {
631   PetscFunctionBegin;
632   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
633   PetscValidPointer(name, 2);
634   PetscUseMethod(viewer, "PetscViewerFileGetName_C", (PetscViewer, const char **), (viewer, name));
635   PetscFunctionReturn(0);
636 }
637 
638 PetscErrorCode PetscViewerFileGetName_ASCII(PetscViewer viewer, const char **name) {
639   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
640 
641   PetscFunctionBegin;
642   *name = vascii->filename;
643   PetscFunctionReturn(0);
644 }
645 
646 PetscErrorCode PetscViewerFileSetName_ASCII(PetscViewer viewer, const char name[]) {
647   size_t             len;
648   char               fname[PETSC_MAX_PATH_LEN], *gz;
649   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
650   PetscBool          isstderr, isstdout;
651   PetscMPIInt        rank;
652 
653   PetscFunctionBegin;
654   PetscCall(PetscViewerFileClose_ASCII(viewer));
655   if (!name) PetscFunctionReturn(0);
656   PetscCall(PetscStrallocpy(name, &vascii->filename));
657 
658   /* Is this file to be compressed */
659   vascii->storecompressed = PETSC_FALSE;
660 
661   PetscCall(PetscStrstr(vascii->filename, ".gz", &gz));
662   if (gz) {
663     PetscCall(PetscStrlen(gz, &len));
664     if (len == 3) {
665       PetscCheck(vascii->mode == FILE_MODE_WRITE, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Cannot open ASCII PetscViewer file that is compressed; uncompress it manually first");
666       *gz                     = 0;
667       vascii->storecompressed = PETSC_TRUE;
668     }
669   }
670   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
671   if (rank == 0) {
672     PetscCall(PetscStrcmp(name, "stderr", &isstderr));
673     PetscCall(PetscStrcmp(name, "stdout", &isstdout));
674     /* empty filename means stdout */
675     if (name[0] == 0) isstdout = PETSC_TRUE;
676     if (isstderr) vascii->fd = PETSC_STDERR;
677     else if (isstdout) vascii->fd = PETSC_STDOUT;
678     else {
679       PetscCall(PetscFixFilename(name, fname));
680       switch (vascii->mode) {
681       case FILE_MODE_READ: vascii->fd = fopen(fname, "r"); break;
682       case FILE_MODE_WRITE: vascii->fd = fopen(fname, "w"); break;
683       case FILE_MODE_APPEND: vascii->fd = fopen(fname, "a"); break;
684       case FILE_MODE_UPDATE:
685         vascii->fd = fopen(fname, "r+");
686         if (!vascii->fd) vascii->fd = fopen(fname, "w+");
687         break;
688       case FILE_MODE_APPEND_UPDATE:
689         /* I really want a file which is opened at the end for updating,
690            not a+, which opens at the beginning, but makes writes at the end.
691         */
692         vascii->fd = fopen(fname, "r+");
693         if (!vascii->fd) vascii->fd = fopen(fname, "w+");
694         else PetscCall(fseek(vascii->fd, 0, SEEK_END));
695         break;
696       default: SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Unsupported file mode %s", PetscFileModes[vascii->mode]);
697       }
698       PetscCheck(vascii->fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open PetscViewer file: %s", fname);
699     }
700   }
701 #if defined(PETSC_USE_LOG)
702   PetscLogObjectState((PetscObject)viewer, "File: %s", name);
703 #endif
704   PetscFunctionReturn(0);
705 }
706 
707 PetscErrorCode PetscViewerGetSubViewer_ASCII(PetscViewer viewer, MPI_Comm subcomm, PetscViewer *outviewer) {
708   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data, *ovascii;
709 
710   PetscFunctionBegin;
711   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
712   PetscCheck(!vascii->sviewer, PETSC_COMM_SELF, PETSC_ERR_ORDER, "SubViewer already obtained from PetscViewer and not restored");
713   /*
714      The following line is a bug; it does another PetscViewerASCIIPushSynchronized() on viewer, but if it is removed the code won't work
715      because it relies on this behavior in other places. In particular this line causes the synchronized flush to occur when the viewer is destroyed
716      (since the count never gets to zero) in some examples this displays information that otherwise would be lost
717 
718      This code also means another call to PetscViewerASCIIPopSynchronized() must be made after the PetscViewerRestoreSubViewer(), see, for example,
719      PCView_GASM().
720   */
721   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
722   PetscCall(PetscViewerCreate(subcomm, outviewer));
723   PetscCall(PetscViewerSetType(*outviewer, PETSCVIEWERASCII));
724   PetscCall(PetscViewerASCIIPushSynchronized(*outviewer));
725   ovascii            = (PetscViewer_ASCII *)(*outviewer)->data;
726   ovascii->fd        = vascii->fd;
727   ovascii->tab       = vascii->tab;
728   ovascii->closefile = PETSC_FALSE;
729 
730   vascii->sviewer                                      = *outviewer;
731   (*outviewer)->format                                 = viewer->format;
732   ((PetscViewer_ASCII *)((*outviewer)->data))->bviewer = viewer;
733   (*outviewer)->ops->destroy                           = PetscViewerDestroy_ASCII_SubViewer;
734   PetscFunctionReturn(0);
735 }
736 
737 PetscErrorCode PetscViewerRestoreSubViewer_ASCII(PetscViewer viewer, MPI_Comm comm, PetscViewer *outviewer) {
738   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
739 
740   PetscFunctionBegin;
741   PetscCheck(ascii->sviewer, PETSC_COMM_SELF, PETSC_ERR_ORDER, "SubViewer never obtained from PetscViewer");
742   PetscCheck(ascii->sviewer == *outviewer, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "This PetscViewer did not generate this SubViewer");
743 
744   PetscCall(PetscViewerASCIIPopSynchronized(*outviewer));
745   ascii->sviewer             = NULL;
746   (*outviewer)->ops->destroy = PetscViewerDestroy_ASCII;
747   PetscCall(PetscViewerDestroy(outviewer));
748   PetscCall(PetscViewerASCIIPopSynchronized(viewer));
749   PetscFunctionReturn(0);
750 }
751 
752 PetscErrorCode PetscViewerView_ASCII(PetscViewer v, PetscViewer viewer) {
753   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)v->data;
754 
755   PetscFunctionBegin;
756   if (ascii->filename) PetscCall(PetscViewerASCIIPrintf(viewer, "Filename: %s\n", ascii->filename));
757   PetscFunctionReturn(0);
758 }
759 
760 /*MC
761    PETSCVIEWERASCII - A viewer that prints to stdout or an ASCII file
762 
763 .seealso: `PETSC_VIEWER_STDOUT_()`, `PETSC_VIEWER_STDOUT_SELF`, `PETSC_VIEWER_STDOUT_WORLD`, `PetscViewerCreate()`, `PetscViewerASCIIOpen()`,
764           `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERBINARY`, `PETSCVIEWERMATLAB`,
765           `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscViewerType`, `PetscViewerSetType()`
766 
767   Level: beginner
768 
769 M*/
770 PETSC_EXTERN PetscErrorCode PetscViewerCreate_ASCII(PetscViewer viewer) {
771   PetscViewer_ASCII *vascii;
772 
773   PetscFunctionBegin;
774   PetscCall(PetscNewLog(viewer, &vascii));
775   viewer->data = (void *)vascii;
776 
777   viewer->ops->destroy          = PetscViewerDestroy_ASCII;
778   viewer->ops->flush            = PetscViewerFlush_ASCII;
779   viewer->ops->getsubviewer     = PetscViewerGetSubViewer_ASCII;
780   viewer->ops->restoresubviewer = PetscViewerRestoreSubViewer_ASCII;
781   viewer->ops->view             = PetscViewerView_ASCII;
782   viewer->ops->read             = PetscViewerASCIIRead;
783 
784   /* defaults to stdout unless set with PetscViewerFileSetName() */
785   vascii->fd        = PETSC_STDOUT;
786   vascii->mode      = FILE_MODE_WRITE;
787   vascii->bviewer   = NULL;
788   vascii->subviewer = NULL;
789   vascii->sviewer   = NULL;
790   vascii->tab       = 0;
791   vascii->tab_store = 0;
792   vascii->filename  = NULL;
793   vascii->closefile = PETSC_TRUE;
794 
795   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", PetscViewerFileSetName_ASCII));
796   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetName_C", PetscViewerFileGetName_ASCII));
797   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", PetscViewerFileGetMode_ASCII));
798   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetMode_C", PetscViewerFileSetMode_ASCII));
799   PetscFunctionReturn(0);
800 }
801 
802 /*@C
803     PetscViewerASCIISynchronizedPrintf - Prints synchronized output to the specified file from
804     several processors.  Output of the first processor is followed by that of the
805     second, etc.
806 
807     Not Collective, must call collective PetscViewerFlush() to get the results out
808 
809     Input Parameters:
810 +   viewer - the ASCII PetscViewer
811 -   format - the usual printf() format string
812 
813     Level: intermediate
814 
815     Notes:
816     You must have previously called PetscViewerASCIIPushSynchronized() to allow this routine to be called.
817     Then you can do multiple independent calls to this routine.
818     The actual synchronized print is then done using PetscViewerFlush().
819     PetscViewerASCIIPopSynchronized() should be then called if we are already done with the synchronized output
820     to conclude the "synchronized session".
821     So the typical calling sequence looks like
822 $ PetscViewerASCIIPushSynchronized(viewer);
823 $ PetscViewerASCIISynchronizedPrintf(viewer, ...);
824 $ PetscViewerASCIISynchronizedPrintf(viewer, ...);
825 $ ...
826 $ PetscViewerFlush(viewer);
827 $ PetscViewerASCIISynchronizedPrintf(viewer, ...);
828 $ PetscViewerASCIISynchronizedPrintf(viewer, ...);
829 $ ...
830 $ PetscViewerFlush(viewer);
831 $ PetscViewerASCIIPopSynchronized(viewer);
832 
833     Fortran Note:
834       Can only print a single character* string
835 
836 .seealso: `PetscViewerASCIIPushSynchronized()`, `PetscViewerFlush()`, `PetscViewerASCIIPopSynchronized()`,
837           `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIIOpen()`,
838           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`
839 @*/
840 PetscErrorCode PetscViewerASCIISynchronizedPrintf(PetscViewer viewer, const char format[], ...) {
841   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
842   PetscMPIInt        rank;
843   PetscInt           tab = vascii->tab;
844   MPI_Comm           comm;
845   FILE              *fp;
846   PetscBool          iascii, hasbviewer = PETSC_FALSE;
847   int                err;
848 
849   PetscFunctionBegin;
850   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
851   PetscValidCharPointer(format, 2);
852   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
853   PetscCheck(iascii, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not ASCII PetscViewer");
854   PetscCheck(vascii->allowsynchronized, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "First call PetscViewerASCIIPushSynchronized() to allow this call");
855 
856   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
857   PetscCallMPI(MPI_Comm_rank(comm, &rank));
858 
859   if (vascii->bviewer) {
860     hasbviewer = PETSC_TRUE;
861     if (rank == 0) {
862       vascii = (PetscViewer_ASCII *)vascii->bviewer->data;
863       PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
864       PetscCallMPI(MPI_Comm_rank(comm, &rank));
865     }
866   }
867 
868   fp = vascii->fd;
869 
870   if (rank == 0 && !hasbviewer) { /* First processor prints immediately to fp */
871     va_list     Argp;
872     /* flush my own messages that I may have queued up */
873     PrintfQueue next = vascii->petsc_printfqueuebase, previous;
874     PetscInt    i;
875     for (i = 0; i < vascii->petsc_printfqueuelength; i++) {
876       PetscCall(PetscFPrintf(comm, fp, "%s", next->string));
877       previous = next;
878       next     = next->next;
879       PetscCall(PetscFree(previous->string));
880       PetscCall(PetscFree(previous));
881     }
882     vascii->petsc_printfqueue       = NULL;
883     vascii->petsc_printfqueuelength = 0;
884 
885     while (tab--) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fp, "  "));
886 
887     va_start(Argp, format);
888     PetscCall((*PetscVFPrintf)(fp, format, Argp));
889     err = fflush(fp);
890     PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fflush() failed on file");
891     if (petsc_history) {
892       va_start(Argp, format);
893       PetscCall((*PetscVFPrintf)(petsc_history, format, Argp));
894       err = fflush(petsc_history);
895       PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fflush() failed on file");
896     }
897     va_end(Argp);
898   } else { /* other processors add to queue */
899     char       *string;
900     va_list     Argp;
901     size_t      fullLength;
902     PrintfQueue next;
903 
904     PetscCall(PetscNew(&next));
905     if (vascii->petsc_printfqueue) {
906       vascii->petsc_printfqueue->next = next;
907       vascii->petsc_printfqueue       = next;
908     } else {
909       vascii->petsc_printfqueuebase = vascii->petsc_printfqueue = next;
910     }
911     vascii->petsc_printfqueuelength++;
912     next->size = QUEUESTRINGSIZE;
913     PetscCall(PetscCalloc1(next->size, &next->string));
914     string = next->string;
915     tab *= 2;
916     while (tab--) *string++ = ' ';
917     va_start(Argp, format);
918     PetscCall(PetscVSNPrintf(string, next->size - 2 * vascii->tab, format, &fullLength, Argp));
919     va_end(Argp);
920     if (fullLength > (size_t)(next->size - 2 * vascii->tab)) {
921       PetscCall(PetscFree(next->string));
922       next->size = fullLength + 2 * vascii->tab;
923       PetscCall(PetscCalloc1(next->size, &next->string));
924       string = next->string;
925       tab    = 2 * vascii->tab;
926       while (tab--) *string++ = ' ';
927       va_start(Argp, format);
928       PetscCall(PetscVSNPrintf(string, next->size - 2 * vascii->tab, format, NULL, Argp));
929       va_end(Argp);
930     }
931   }
932   PetscFunctionReturn(0);
933 }
934 
935 /*@C
936    PetscViewerASCIIRead - Reads from a ASCII file
937 
938    Only process 0 in the PetscViewer may call this
939 
940    Input Parameters:
941 +  viewer - the ascii viewer
942 .  data - location to write the data
943 .  num - number of items of data to read
944 -  datatype - type of data to read
945 
946    Output Parameters:
947 .  count - number of items of data actually read, or NULL
948 
949    Level: beginner
950 
951 .seealso: `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetName()`
952           `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`, `PetscViewerBinaryGetDescriptor()`,
953           `PetscViewerBinaryGetInfoPointer()`, `PetscFileMode`, `PetscViewer`, `PetscViewerBinaryRead()`
954 @*/
955 PetscErrorCode PetscViewerASCIIRead(PetscViewer viewer, void *data, PetscInt num, PetscInt *count, PetscDataType dtype) {
956   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
957   FILE              *fd     = vascii->fd;
958   PetscInt           i;
959   int                ret = 0;
960   PetscMPIInt        rank;
961 
962   PetscFunctionBegin;
963   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
964   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
965   PetscCheck(rank == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Can only be called from process 0 in the PetscViewer");
966   for (i = 0; i < num; i++) {
967     if (dtype == PETSC_CHAR) ret = fscanf(fd, "%c", &(((char *)data)[i]));
968     else if (dtype == PETSC_STRING) ret = fscanf(fd, "%s", &(((char *)data)[i]));
969     else if (dtype == PETSC_INT) ret = fscanf(fd, "%" PetscInt_FMT, &(((PetscInt *)data)[i]));
970     else if (dtype == PETSC_ENUM) ret = fscanf(fd, "%d", &(((int *)data)[i]));
971     else if (dtype == PETSC_INT64) ret = fscanf(fd, "%" PetscInt64_FMT, &(((PetscInt64 *)data)[i]));
972     else if (dtype == PETSC_LONG) ret = fscanf(fd, "%ld", &(((long *)data)[i]));
973     else if (dtype == PETSC_FLOAT) ret = fscanf(fd, "%f", &(((float *)data)[i]));
974     else if (dtype == PETSC_DOUBLE) ret = fscanf(fd, "%lg", &(((double *)data)[i]));
975 #if defined(PETSC_USE_REAL___FLOAT128)
976     else if (dtype == PETSC___FLOAT128) {
977       double tmp;
978       ret                     = fscanf(fd, "%lg", &tmp);
979       ((__float128 *)data)[i] = tmp;
980     }
981 #endif
982     else
983       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Data type %d not supported", (int)dtype);
984     PetscCheck(ret, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Conversion error for data type %d", (int)dtype);
985     if (ret < 0) break; /* Proxy for EOF, need to check for it in configure */
986   }
987   if (count) *count = i;
988   else PetscCheck(ret >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Insufficient data, read only %" PetscInt_FMT " < %" PetscInt_FMT " items", i, num);
989   PetscFunctionReturn(0);
990 }
991