(root)/
glibc-2.38/
stdio-common/
reg-modifier.c
       1  /* Copyright (C) 2009-2023 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  #include <errno.h>
      19  #include <limits.h>
      20  #include <printf.h>
      21  #include <stdlib.h>
      22  #include <wchar.h>
      23  #include <libc-lock.h>
      24  
      25  
      26  struct printf_modifier_record
      27  {
      28    struct printf_modifier_record *next;
      29    int bit;
      30    wchar_t str[0];
      31  };
      32  
      33  struct printf_modifier_record **__printf_modifier_table attribute_hidden;
      34  
      35  __libc_lock_define_initialized (static, lock)
      36  
      37  /* Bits to hand out.  */
      38  static int next_bit;
      39  
      40  
      41  int
      42  __register_printf_modifier (const wchar_t *str)
      43  {
      44    if (str[0] == L'\0')
      45      {
      46      einval:
      47        __set_errno (EINVAL);
      48        return -1;
      49      }
      50  
      51    const wchar_t *wc = str;
      52    while (*wc != L'\0')
      53      if (*wc < 0 || *wc > (wchar_t) UCHAR_MAX)
      54        goto einval;
      55      else
      56        ++wc;
      57  
      58    if (next_bit / 8 == sizeof (((struct printf_info *) NULL)->user))
      59      {
      60        __set_errno (ENOSPC);
      61        return -1;
      62      }
      63  
      64    int result = -1;
      65    __libc_lock_lock (lock);
      66  
      67    if (__printf_modifier_table == NULL)
      68      {
      69        __printf_modifier_table = calloc (UCHAR_MAX,
      70  					sizeof (*__printf_modifier_table));
      71        if (__printf_modifier_table == NULL)
      72  	goto out;
      73      }
      74  
      75    /* Create enough room for the string.  But we don't need the first
      76       character. */
      77    struct printf_modifier_record *newp = malloc (sizeof (*newp)
      78  						+ ((wc - str)
      79  						   * sizeof (wchar_t)));
      80    if (newp == NULL)
      81      goto out;
      82  
      83    newp->next = __printf_modifier_table[(unsigned char) *str];
      84    newp->bit = 1 << next_bit++;
      85    __wmemcpy (newp->str, str + 1, wc - str);
      86  
      87    __printf_modifier_table[(unsigned char) *str] = newp;
      88  
      89    result = newp->bit;
      90  
      91   out:
      92    __libc_lock_unlock (lock);
      93  
      94    return result;
      95  }
      96  weak_alias (__register_printf_modifier, register_printf_modifier)
      97  
      98  
      99  #include <stdio.h>
     100  int
     101  attribute_hidden
     102  __handle_registered_modifier_mb (const unsigned char **format,
     103  				 struct printf_info *info)
     104  {
     105    struct printf_modifier_record *runp = __printf_modifier_table[**format];
     106  
     107    int best_bit = 0;
     108    int best_len = 0;
     109    const unsigned char *best_cp = NULL;
     110  
     111    while (runp != NULL)
     112      {
     113        const unsigned char *cp = *format + 1;
     114        wchar_t *fcp = runp->str;
     115  
     116        while (*cp != '\0' && *fcp != L'\0')
     117  	if (*cp != *fcp)
     118  	  break;
     119  	else
     120  	  ++cp, ++fcp;
     121  
     122        if (*fcp == L'\0' && cp - *format > best_len)
     123  	{
     124  	  best_cp = cp;
     125  	  best_len = cp - *format;
     126  	  best_bit = runp->bit;
     127  	}
     128  
     129        runp = runp->next;
     130      }
     131  
     132    if (best_bit != 0)
     133      {
     134        info->user |= best_bit;
     135        *format = best_cp;
     136        return 0;
     137      }
     138  
     139    return 1;
     140  }
     141  
     142  
     143  int
     144  attribute_hidden
     145  __handle_registered_modifier_wc (const unsigned int **format,
     146  				 struct printf_info *info)
     147  {
     148    struct printf_modifier_record *runp = __printf_modifier_table[**format];
     149  
     150    int best_bit = 0;
     151    int best_len = 0;
     152    const unsigned int *best_cp = NULL;
     153  
     154    while (runp != NULL)
     155      {
     156        const unsigned int *cp = *format + 1;
     157        wchar_t *fcp = runp->str;
     158  
     159        while (*cp != '\0' && *fcp != L'\0')
     160  	if (*cp != *fcp)
     161  	  break;
     162  	else
     163  	  ++cp, ++fcp;
     164  
     165        if (*fcp == L'\0' && cp - *format > best_len)
     166  	{
     167  	  best_cp = cp;
     168  	  best_len = cp - *format;
     169  	  best_bit = runp->bit;
     170  	}
     171  
     172        runp = runp->next;
     173      }
     174  
     175    if (best_bit != 0)
     176      {
     177        info->user |= best_bit;
     178        *format = best_cp;
     179        return 0;
     180      }
     181  
     182    return 1;
     183  }
     184  
     185  
     186  void
     187  __libc_printf_freemem (void)
     188  {
     189    if (__printf_modifier_table != NULL)
     190      {
     191        for (int i = 0; i < UCHAR_MAX; ++i)
     192  	{
     193  	  struct printf_modifier_record *runp = __printf_modifier_table[i];
     194  	  while (runp != NULL)
     195  	    {
     196  	      struct printf_modifier_record *oldp = runp;
     197  	      runp = runp->next;
     198  	      free (oldp);
     199  	    }
     200  	}
     201        free (__printf_modifier_table);
     202      }
     203  }