1 /* Copyright (C) 1993-2022 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.
17 
18    As a special exception, if you link the code in this file with
19    files compiled with a GNU compiler to produce an executable,
20    that does not cause the resulting executable to be covered by
21    the GNU Lesser General Public License.  This exception does not
22    however invalidate any other reasons why the executable file
23    might be covered by the GNU Lesser General Public License.
24    This exception applies to code released by its copyright holders
25    in files containing the exception.  */
26 
27 /* Generic or default I/O operations. */
28 
29 #include "libioP.h"
30 #include <stdlib.h>
31 #include <string.h>
32 #include <wchar.h>
33 
34 
35 static int save_for_wbackup (FILE *fp, wchar_t *end_p) __THROW;
36 
37 /* Return minimum _pos markers
38    Assumes the current get area is the main get area. */
39 ssize_t
_IO_least_wmarker(FILE * fp,wchar_t * end_p)40 _IO_least_wmarker (FILE *fp, wchar_t *end_p)
41 {
42   ssize_t least_so_far = end_p - fp->_wide_data->_IO_read_base;
43   struct _IO_marker *mark;
44   for (mark = fp->_markers; mark != NULL; mark = mark->_next)
45     if (mark->_pos < least_so_far)
46       least_so_far = mark->_pos;
47   return least_so_far;
48 }
libc_hidden_def(_IO_least_wmarker)49 libc_hidden_def (_IO_least_wmarker)
50 
51 /* Switch current get area from backup buffer to (start of) main get area. */
52 void
53 _IO_switch_to_main_wget_area (FILE *fp)
54 {
55   wchar_t *tmp;
56   fp->_flags &= ~_IO_IN_BACKUP;
57   /* Swap _IO_read_end and _IO_save_end. */
58   tmp = fp->_wide_data->_IO_read_end;
59   fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_save_end;
60   fp->_wide_data->_IO_save_end= tmp;
61   /* Swap _IO_read_base and _IO_save_base. */
62   tmp = fp->_wide_data->_IO_read_base;
63   fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_save_base;
64   fp->_wide_data->_IO_save_base = tmp;
65   /* Set _IO_read_ptr. */
66   fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_base;
67 }
libc_hidden_def(_IO_switch_to_main_wget_area)68 libc_hidden_def (_IO_switch_to_main_wget_area)
69 
70 
71 /* Switch current get area from main get area to (end of) backup area. */
72 void
73 _IO_switch_to_wbackup_area (FILE *fp)
74 {
75   wchar_t *tmp;
76   fp->_flags |= _IO_IN_BACKUP;
77   /* Swap _IO_read_end and _IO_save_end. */
78   tmp = fp->_wide_data->_IO_read_end;
79   fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_save_end;
80   fp->_wide_data->_IO_save_end = tmp;
81   /* Swap _IO_read_base and _IO_save_base. */
82   tmp = fp->_wide_data->_IO_read_base;
83   fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_save_base;
84   fp->_wide_data->_IO_save_base = tmp;
85   /* Set _IO_read_ptr.  */
86   fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
87 }
libc_hidden_def(_IO_switch_to_wbackup_area)88 libc_hidden_def (_IO_switch_to_wbackup_area)
89 
90 
91 void
92 _IO_wsetb (FILE *f, wchar_t *b, wchar_t *eb, int a)
93 {
94   if (f->_wide_data->_IO_buf_base && !(f->_flags2 & _IO_FLAGS2_USER_WBUF))
95     free (f->_wide_data->_IO_buf_base);
96   f->_wide_data->_IO_buf_base = b;
97   f->_wide_data->_IO_buf_end = eb;
98   if (a)
99     f->_flags2 &= ~_IO_FLAGS2_USER_WBUF;
100   else
101     f->_flags2 |= _IO_FLAGS2_USER_WBUF;
102 }
libc_hidden_def(_IO_wsetb)103 libc_hidden_def (_IO_wsetb)
104 
105 
106 wint_t
107 _IO_wdefault_pbackfail (FILE *fp, wint_t c)
108 {
109   if (fp->_wide_data->_IO_read_ptr > fp->_wide_data->_IO_read_base
110       && !_IO_in_backup (fp)
111       && (wint_t) fp->_IO_read_ptr[-1] == c)
112     --fp->_IO_read_ptr;
113   else
114     {
115       /* Need to handle a filebuf in write mode (switch to read mode). FIXME!*/
116       if (!_IO_in_backup (fp))
117 	{
118 	  /* We need to keep the invariant that the main get area
119 	     logically follows the backup area.  */
120 	  if (fp->_wide_data->_IO_read_ptr > fp->_wide_data->_IO_read_base
121 	      && _IO_have_wbackup (fp))
122 	    {
123 	      if (save_for_wbackup (fp, fp->_wide_data->_IO_read_ptr))
124 		return WEOF;
125 	    }
126 	  else if (!_IO_have_wbackup (fp))
127 	    {
128 	      /* No backup buffer: allocate one. */
129 	      /* Use nshort buffer, if unused? (probably not)  FIXME */
130 	      int backup_size = 128;
131 	      wchar_t *bbuf = (wchar_t *) malloc (backup_size
132 						  * sizeof (wchar_t));
133 	      if (bbuf == NULL)
134 		return WEOF;
135 	      fp->_wide_data->_IO_save_base = bbuf;
136 	      fp->_wide_data->_IO_save_end = (fp->_wide_data->_IO_save_base
137 					      + backup_size);
138 	      fp->_wide_data->_IO_backup_base = fp->_wide_data->_IO_save_end;
139 	    }
140 	  fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr;
141 	  _IO_switch_to_wbackup_area (fp);
142 	}
143       else if (fp->_wide_data->_IO_read_ptr <= fp->_wide_data->_IO_read_base)
144 	{
145 	  /* Increase size of existing backup buffer. */
146 	  size_t new_size;
147 	  size_t old_size = (fp->_wide_data->_IO_read_end
148                              - fp->_wide_data->_IO_read_base);
149 	  wchar_t *new_buf;
150 	  new_size = 2 * old_size;
151 	  new_buf = (wchar_t *) malloc (new_size * sizeof (wchar_t));
152 	  if (new_buf == NULL)
153 	    return WEOF;
154 	  __wmemcpy (new_buf + (new_size - old_size),
155 		     fp->_wide_data->_IO_read_base, old_size);
156 	  free (fp->_wide_data->_IO_read_base);
157 	  _IO_wsetg (fp, new_buf, new_buf + (new_size - old_size),
158 		     new_buf + new_size);
159 	  fp->_wide_data->_IO_backup_base = fp->_wide_data->_IO_read_ptr;
160 	}
161 
162       *--fp->_wide_data->_IO_read_ptr = c;
163     }
164   return c;
165 }
libc_hidden_def(_IO_wdefault_pbackfail)166 libc_hidden_def (_IO_wdefault_pbackfail)
167 
168 
169 void
170 _IO_wdefault_finish (FILE *fp, int dummy)
171 {
172   struct _IO_marker *mark;
173   if (fp->_wide_data->_IO_buf_base && !(fp->_flags2 & _IO_FLAGS2_USER_WBUF))
174     {
175       free (fp->_wide_data->_IO_buf_base);
176       fp->_wide_data->_IO_buf_base = fp->_wide_data->_IO_buf_end = NULL;
177     }
178 
179   for (mark = fp->_markers; mark != NULL; mark = mark->_next)
180     mark->_sbuf = NULL;
181 
182   if (fp->_IO_save_base)
183     {
184       free (fp->_wide_data->_IO_save_base);
185       fp->_IO_save_base = NULL;
186     }
187 
188 #ifdef _IO_MTSAFE_IO
189   if (fp->_lock != NULL)
190     _IO_lock_fini (*fp->_lock);
191 #endif
192 
193   _IO_un_link ((struct _IO_FILE_plus *) fp);
194 }
libc_hidden_def(_IO_wdefault_finish)195 libc_hidden_def (_IO_wdefault_finish)
196 
197 
198 wint_t
199 _IO_wdefault_uflow (FILE *fp)
200 {
201   wint_t wch;
202   wch = _IO_UNDERFLOW (fp);
203   if (wch == WEOF)
204     return WEOF;
205   return *fp->_wide_data->_IO_read_ptr++;
206 }
libc_hidden_def(_IO_wdefault_uflow)207 libc_hidden_def (_IO_wdefault_uflow)
208 
209 
210 wint_t
211 __woverflow (FILE *f, wint_t wch)
212 {
213   if (f->_mode == 0)
214     _IO_fwide (f, 1);
215   return _IO_OVERFLOW (f, wch);
216 }
libc_hidden_def(__woverflow)217 libc_hidden_def (__woverflow)
218 
219 
220 wint_t
221 __wuflow (FILE *fp)
222 {
223   if (fp->_mode < 0 || (fp->_mode == 0 && _IO_fwide (fp, 1) != 1))
224     return WEOF;
225 
226   if (fp->_mode == 0)
227     _IO_fwide (fp, 1);
228   if (_IO_in_put_mode (fp))
229     if (_IO_switch_to_wget_mode (fp) == EOF)
230       return WEOF;
231   if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
232     return *fp->_wide_data->_IO_read_ptr++;
233   if (_IO_in_backup (fp))
234     {
235       _IO_switch_to_main_wget_area (fp);
236       if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
237 	return *fp->_wide_data->_IO_read_ptr++;
238     }
239   if (_IO_have_markers (fp))
240     {
241       if (save_for_wbackup (fp, fp->_wide_data->_IO_read_end))
242 	return WEOF;
243     }
244   else if (_IO_have_wbackup (fp))
245     _IO_free_wbackup_area (fp);
246   return _IO_UFLOW (fp);
247 }
libc_hidden_def(__wuflow)248 libc_hidden_def (__wuflow)
249 
250 wint_t
251 __wunderflow (FILE *fp)
252 {
253   if (fp->_mode < 0 || (fp->_mode == 0 && _IO_fwide (fp, 1) != 1))
254     return WEOF;
255 
256   if (fp->_mode == 0)
257     _IO_fwide (fp, 1);
258   if (_IO_in_put_mode (fp))
259     if (_IO_switch_to_wget_mode (fp) == EOF)
260       return WEOF;
261   if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
262     return *fp->_wide_data->_IO_read_ptr;
263   if (_IO_in_backup (fp))
264     {
265       _IO_switch_to_main_wget_area (fp);
266       if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
267 	return *fp->_wide_data->_IO_read_ptr;
268     }
269   if (_IO_have_markers (fp))
270     {
271       if (save_for_wbackup (fp, fp->_wide_data->_IO_read_end))
272 	return WEOF;
273     }
274   else if (_IO_have_backup (fp))
275     _IO_free_wbackup_area (fp);
276   return _IO_UNDERFLOW (fp);
277 }
libc_hidden_def(__wunderflow)278 libc_hidden_def (__wunderflow)
279 
280 
281 size_t
282 _IO_wdefault_xsputn (FILE *f, const void *data, size_t n)
283 {
284   const wchar_t *s = (const wchar_t *) data;
285   size_t more = n;
286   if (more <= 0)
287     return 0;
288   for (;;)
289     {
290       /* Space available. */
291       ssize_t count = (f->_wide_data->_IO_write_end
292                        - f->_wide_data->_IO_write_ptr);
293       if (count > 0)
294 	{
295 	  if ((size_t) count > more)
296 	    count = more;
297 	  if (count > 20)
298 	    {
299 	      f->_wide_data->_IO_write_ptr =
300 		__wmempcpy (f->_wide_data->_IO_write_ptr, s, count);
301 	      s += count;
302             }
303 	  else if (count <= 0)
304 	    count = 0;
305 	  else
306 	    {
307 	      wchar_t *p = f->_wide_data->_IO_write_ptr;
308 	      ssize_t i;
309 	      for (i = count; --i >= 0; )
310 		*p++ = *s++;
311 	      f->_wide_data->_IO_write_ptr = p;
312             }
313 	  more -= count;
314         }
315       if (more == 0 || __woverflow (f, *s++) == WEOF)
316 	break;
317       more--;
318     }
319   return n - more;
320 }
libc_hidden_def(_IO_wdefault_xsputn)321 libc_hidden_def (_IO_wdefault_xsputn)
322 
323 
324 size_t
325 _IO_wdefault_xsgetn (FILE *fp, void *data, size_t n)
326 {
327   size_t more = n;
328   wchar_t *s = (wchar_t*) data;
329   for (;;)
330     {
331       /* Data available. */
332       ssize_t count = (fp->_wide_data->_IO_read_end
333                        - fp->_wide_data->_IO_read_ptr);
334       if (count > 0)
335 	{
336 	  if ((size_t) count > more)
337 	    count = more;
338 	  if (count > 20)
339 	    {
340 	      s = __wmempcpy (s, fp->_wide_data->_IO_read_ptr, count);
341 	      fp->_wide_data->_IO_read_ptr += count;
342 	    }
343 	  else if (count <= 0)
344 	    count = 0;
345 	  else
346 	    {
347 	      wchar_t *p = fp->_wide_data->_IO_read_ptr;
348 	      int i = (int) count;
349 	      while (--i >= 0)
350 		*s++ = *p++;
351 	      fp->_wide_data->_IO_read_ptr = p;
352             }
353             more -= count;
354         }
355       if (more == 0 || __wunderflow (fp) == WEOF)
356 	break;
357     }
358   return n - more;
359 }
libc_hidden_def(_IO_wdefault_xsgetn)360 libc_hidden_def (_IO_wdefault_xsgetn)
361 
362 
363 void
364 _IO_wdoallocbuf (FILE *fp)
365 {
366   if (fp->_wide_data->_IO_buf_base)
367     return;
368   if (!(fp->_flags & _IO_UNBUFFERED))
369     if ((wint_t)_IO_WDOALLOCATE (fp) != WEOF)
370       return;
371   _IO_wsetb (fp, fp->_wide_data->_shortbuf,
372 		     fp->_wide_data->_shortbuf + 1, 0);
373 }
libc_hidden_def(_IO_wdoallocbuf)374 libc_hidden_def (_IO_wdoallocbuf)
375 
376 
377 int
378 _IO_wdefault_doallocate (FILE *fp)
379 {
380   wchar_t *buf = (wchar_t *)malloc (BUFSIZ);
381   if (__glibc_unlikely (buf == NULL))
382     return EOF;
383 
384   _IO_wsetb (fp, buf, buf + BUFSIZ / sizeof *buf, 1);
385   return 1;
386 }
libc_hidden_def(_IO_wdefault_doallocate)387 libc_hidden_def (_IO_wdefault_doallocate)
388 
389 
390 int
391 _IO_switch_to_wget_mode (FILE *fp)
392 {
393   if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
394     if ((wint_t)_IO_WOVERFLOW (fp, WEOF) == WEOF)
395       return EOF;
396   if (_IO_in_backup (fp))
397     fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_backup_base;
398   else
399     {
400       fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_buf_base;
401       if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
402 	fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
403     }
404   fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_write_ptr;
405 
406   fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr
407     = fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_read_ptr;
408 
409   fp->_flags &= ~_IO_CURRENTLY_PUTTING;
410   return 0;
411 }
libc_hidden_def(_IO_switch_to_wget_mode)412 libc_hidden_def (_IO_switch_to_wget_mode)
413 
414 void
415 _IO_free_wbackup_area (FILE *fp)
416 {
417   if (_IO_in_backup (fp))
418     _IO_switch_to_main_wget_area (fp);  /* Just in case. */
419   free (fp->_wide_data->_IO_save_base);
420   fp->_wide_data->_IO_save_base = NULL;
421   fp->_wide_data->_IO_save_end = NULL;
422   fp->_wide_data->_IO_backup_base = NULL;
423 }
libc_hidden_def(_IO_free_wbackup_area)424 libc_hidden_def (_IO_free_wbackup_area)
425 
426 static int
427 save_for_wbackup (FILE *fp, wchar_t *end_p)
428 {
429   /* Append [_IO_read_base..end_p] to backup area. */
430   ssize_t least_mark = _IO_least_wmarker (fp, end_p);
431   /* needed_size is how much space we need in the backup area. */
432   size_t needed_size = ((end_p - fp->_wide_data->_IO_read_base)
433                         - least_mark);
434   /* FIXME: Dubious arithmetic if pointers are NULL */
435   size_t current_Bsize = (fp->_wide_data->_IO_save_end
436                           - fp->_wide_data->_IO_save_base);
437   size_t avail; /* Extra space available for future expansion. */
438   ssize_t delta;
439   struct _IO_marker *mark;
440   if (needed_size > current_Bsize)
441     {
442       wchar_t *new_buffer;
443       avail = 100;
444       new_buffer = (wchar_t *) malloc ((avail + needed_size)
445 				       * sizeof (wchar_t));
446       if (new_buffer == NULL)
447 	return EOF;		/* FIXME */
448       if (least_mark < 0)
449 	{
450 	  __wmempcpy (__wmempcpy (new_buffer + avail,
451 				  fp->_wide_data->_IO_save_end + least_mark,
452 				  -least_mark),
453 		      fp->_wide_data->_IO_read_base,
454 		      end_p - fp->_wide_data->_IO_read_base);
455 	}
456       else
457 	{
458 	  __wmemcpy (new_buffer + avail,
459 		     fp->_wide_data->_IO_read_base + least_mark,
460 		     needed_size);
461 	}
462       free (fp->_wide_data->_IO_save_base);
463       fp->_wide_data->_IO_save_base = new_buffer;
464       fp->_wide_data->_IO_save_end = new_buffer + avail + needed_size;
465     }
466   else
467     {
468       avail = current_Bsize - needed_size;
469       if (least_mark < 0)
470 	{
471 	  __wmemmove (fp->_wide_data->_IO_save_base + avail,
472 		      fp->_wide_data->_IO_save_end + least_mark,
473 		      -least_mark);
474 	  __wmemcpy (fp->_wide_data->_IO_save_base + avail - least_mark,
475 		     fp->_wide_data->_IO_read_base,
476 		     end_p - fp->_wide_data->_IO_read_base);
477 	}
478       else if (needed_size > 0)
479 	__wmemcpy (fp->_wide_data->_IO_save_base + avail,
480 		   fp->_wide_data->_IO_read_base + least_mark,
481 		   needed_size);
482     }
483   fp->_wide_data->_IO_backup_base = fp->_wide_data->_IO_save_base + avail;
484   /* Adjust all the streammarkers. */
485   delta = end_p - fp->_wide_data->_IO_read_base;
486   for (mark = fp->_markers; mark != NULL; mark = mark->_next)
487     mark->_pos -= delta;
488   return 0;
489 }
490 
491 wint_t
_IO_sputbackwc(FILE * fp,wint_t c)492 _IO_sputbackwc (FILE *fp, wint_t c)
493 {
494   wint_t result;
495 
496   if (fp->_wide_data->_IO_read_ptr > fp->_wide_data->_IO_read_base
497       && (wchar_t)fp->_wide_data->_IO_read_ptr[-1] == (wchar_t) c)
498     {
499       fp->_wide_data->_IO_read_ptr--;
500       result = c;
501     }
502   else
503     result = _IO_PBACKFAIL (fp, c);
504 
505   if (result != WEOF)
506     fp->_flags &= ~_IO_EOF_SEEN;
507 
508   return result;
509 }
libc_hidden_def(_IO_sputbackwc)510 libc_hidden_def (_IO_sputbackwc)
511 
512 wint_t
513 _IO_sungetwc (FILE *fp)
514 {
515   wint_t result;
516 
517   if (fp->_wide_data->_IO_read_ptr > fp->_wide_data->_IO_read_base)
518     {
519       fp->_wide_data->_IO_read_ptr--;
520       result = *fp->_wide_data->_IO_read_ptr;
521     }
522   else
523     result = _IO_PBACKFAIL (fp, EOF);
524 
525   if (result != WEOF)
526     fp->_flags &= ~_IO_EOF_SEEN;
527 
528   return result;
529 }
530 
531 
532 unsigned
_IO_adjust_wcolumn(unsigned start,const wchar_t * line,int count)533 _IO_adjust_wcolumn (unsigned start, const wchar_t *line, int count)
534 {
535   const wchar_t *ptr = line + count;
536   while (ptr > line)
537     if (*--ptr == L'\n')
538       return line + count - ptr - 1;
539   return start + count;
540 }
541 
542 void
_IO_init_wmarker(struct _IO_marker * marker,FILE * fp)543 _IO_init_wmarker (struct _IO_marker *marker, FILE *fp)
544 {
545   marker->_sbuf = fp;
546   if (_IO_in_put_mode (fp))
547     _IO_switch_to_wget_mode (fp);
548   if (_IO_in_backup (fp))
549     marker->_pos = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end;
550   else
551     marker->_pos = (fp->_wide_data->_IO_read_ptr
552 		    - fp->_wide_data->_IO_read_base);
553 
554   /* Should perhaps sort the chain? */
555   marker->_next = fp->_markers;
556   fp->_markers = marker;
557 }
558 
559 #define BAD_DELTA EOF
560 
561 /* Return difference between MARK and current position of MARK's stream. */
562 int
_IO_wmarker_delta(struct _IO_marker * mark)563 _IO_wmarker_delta (struct _IO_marker *mark)
564 {
565   int cur_pos;
566   if (mark->_sbuf == NULL)
567     return BAD_DELTA;
568   if (_IO_in_backup (mark->_sbuf))
569     cur_pos = (mark->_sbuf->_wide_data->_IO_read_ptr
570 	       - mark->_sbuf->_wide_data->_IO_read_end);
571   else
572     cur_pos = (mark->_sbuf->_wide_data->_IO_read_ptr
573 	       - mark->_sbuf->_wide_data->_IO_read_base);
574   return mark->_pos - cur_pos;
575 }
576 
577 int
_IO_seekwmark(FILE * fp,struct _IO_marker * mark,int delta)578 _IO_seekwmark (FILE *fp, struct _IO_marker *mark, int delta)
579 {
580   if (mark->_sbuf != fp)
581     return EOF;
582  if (mark->_pos >= 0)
583     {
584       if (_IO_in_backup (fp))
585 	_IO_switch_to_main_wget_area (fp);
586       fp->_wide_data->_IO_read_ptr = (fp->_wide_data->_IO_read_base
587 				      + mark->_pos);
588     }
589   else
590     {
591       if (!_IO_in_backup (fp))
592 	_IO_switch_to_wbackup_area (fp);
593       fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end + mark->_pos;
594     }
595   return 0;
596 }
597 
598 void
_IO_unsave_wmarkers(FILE * fp)599 _IO_unsave_wmarkers (FILE *fp)
600 {
601   struct _IO_marker *mark = fp->_markers;
602   if (mark)
603     {
604       fp->_markers = 0;
605     }
606 
607   if (_IO_have_backup (fp))
608     _IO_free_wbackup_area (fp);
609 }
610