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