[v3,0/7] Fix some libm static issues
[platform/upstream/glibc.git] / libio / wgenops.c
1 /* Copyright (C) 1993-2024 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
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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
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 }
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
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
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
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
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
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 }