(root)/
glib-2.79.0/
glib/
tests/
constructor-helper.c
       1  /* constructor-helpers.c - Helper library for the constructor test
       2   *
       3   * Copyright © 2023 Luca Bacci
       4   *
       5   * SPDX-License-Identifier: LGPL-2.1-or-later
       6   *
       7   * This library is free software; you can redistribute it and/or
       8   * modify it under the terms of the GNU Lesser General Public
       9   * License as published by the Free Software Foundation; either
      10   * version 2.1 of the License, or (at your option) any later version.
      11   *
      12   * This library is distributed in the hope that it will be useful,
      13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15   * Lesser General Public License for more details.
      16   *
      17   * You should have received a copy of the GNU Lesser General Public License
      18   * along with this library; if not, see <http://www.gnu.org/licenses/>.
      19   */
      20  
      21  /* This helper library manages a set of strings. Strings can be added,
      22   * removed and checked for presence. This library does not call into
      23   * libc, so can be used from module constructors in a safe manner on
      24   * a wide range of operating systems.
      25   *
      26   * GLib is used only for assertions or hard errors; in such cases we
      27   * don't really care about supported libc calls, as the test ought to
      28   * fail anyway.
      29   */
      30  
      31  #include <stddef.h> /* for size_t */
      32  
      33  #include <glib.h>
      34  
      35  #if defined (_MSC_VER)
      36  #  pragma optimize ("", off)
      37  #else
      38  #  if defined (__clang__)
      39  #    pragma clang optimize off
      40  #  elif defined (__GNUC__)
      41  #    pragma GCC optimize ("O0")
      42  #  endif
      43  #endif
      44  
      45  #if defined(_WIN32)
      46    #define MODULE_EXPORT \
      47      __declspec (dllexport)
      48  #elif defined (__GNUC__)
      49    #define MODULE_EXPORT \
      50      __attribute__((visibility("default")))
      51  #else
      52    #define MODULE_EXPORT
      53  #endif
      54  
      55  char buffer[500];
      56  size_t position;
      57  
      58  MODULE_EXPORT
      59  void string_add (const char *string);
      60  
      61  MODULE_EXPORT
      62  void string_add_exclusive (const char *string);
      63  
      64  MODULE_EXPORT
      65  int string_remove (const char *string);
      66  
      67  MODULE_EXPORT
      68  int string_find (const char *string);
      69  
      70  MODULE_EXPORT
      71  void string_check (const char *string);
      72  
      73  static size_t
      74  strlen_ (const char *string)
      75  {
      76    size_t i = 0;
      77  
      78    g_assert_nonnull (string);
      79  
      80    while (string[i] != 0)
      81      i++;
      82  
      83    return i;
      84  }
      85  
      86  static void
      87  memmove_ (char *buf,
      88            size_t from,
      89            size_t size,
      90            size_t to)
      91  {
      92    g_assert_true (to <= from);
      93  
      94    for (size_t i = 0; i < size; i++)
      95      buffer[to + i] = buffer[from + i];
      96  }
      97  
      98  static void
      99  memcpy_ (char *dst,
     100           const char *src,
     101           size_t size)
     102  {
     103    for (size_t i = 0; i < size; i++)
     104      dst[i] = src[i];
     105  }
     106  
     107  static void
     108  memset_ (char   *dst,
     109           char    val,
     110           size_t  size)
     111  {
     112    for (size_t i = 0; i < size; i++)
     113      dst[i] = val;
     114  }
     115  
     116  static size_t
     117  string_find_index_ (const char *string)
     118  {
     119    size_t string_len;
     120    size_t i = 0;
     121  
     122    g_assert_nonnull (string);
     123    g_assert_true ((string_len = strlen_ (string)) > 0);
     124  
     125    for (i = 0; (i < sizeof (buffer) - position) && (buffer[i] != 0);)
     126      {
     127        const char *iter = &buffer[i];
     128        size_t len = strlen_ (iter);
     129  
     130        if (len == string_len && strcmp (iter, string) == 0)
     131          return i;
     132  
     133        i += len + 1;
     134      }
     135  
     136    return sizeof (buffer);
     137  }
     138  
     139  /**< private >
     140   * string_add:
     141   *
     142   * @string: NULL-terminated string. Must not be empty
     143   *
     144   * Adds @string to the set
     145   */
     146  MODULE_EXPORT
     147  void
     148  string_add (const char *string)
     149  {
     150    size_t len, size;
     151  
     152    g_assert_nonnull (string);
     153    g_assert_true ((len = strlen_ (string)) > 0);
     154  
     155    size = len + 1;
     156  
     157    if (size > sizeof (buffer) - position)
     158      g_error ("Not enough space in the buffer");
     159  
     160    memcpy_ (buffer + position, string, size);
     161  
     162    position += size;
     163  }
     164  
     165  /**< private >
     166   * string_add_exclusive:
     167   *
     168   * @string: NULL-terminated string. Must not be empty
     169   *
     170   * Adds @string to the set, asserting that it's not already present.
     171   */
     172  MODULE_EXPORT
     173  void
     174  string_add_exclusive (const char *string)
     175  {
     176    if (string_find_index_ (string) < sizeof (buffer))
     177      g_error ("string %s already set", string);
     178  
     179    string_add (string);
     180  }
     181  
     182  /**< private >
     183   * string_remove:
     184   *
     185   * @string: NULL-terminated string. Must not be empty
     186   *
     187   * Removes the first occurrence of @string from the set.
     188   *
     189   * Returns: 1 if the string was removed, 0 otherwise.
     190   */
     191  MODULE_EXPORT
     192  int
     193  string_remove (const char *string)
     194  {
     195    size_t index = string_find_index_ (string);
     196    size_t len, size;
     197  
     198    if (index >= sizeof (buffer))
     199      return 0;
     200  
     201    g_assert_true ((len = strlen_ (string)) > 0);
     202    size = len + 1;
     203  
     204    memmove_ (buffer, index + size, index, position - (index + size));
     205  
     206    position -= size;
     207  
     208    memset_ (buffer + position, 0, size);
     209  
     210    return 1;
     211  }
     212  
     213  /**< private >
     214   * string_find:
     215   *
     216   * @string: NULL-terminated string. Must not be empty
     217   *
     218   * Returns 1 if the string is present, 0 otherwise
     219   */
     220  MODULE_EXPORT
     221  int string_find (const char *string)
     222  {
     223    return string_find_index_ (string) < sizeof (buffer);
     224  }
     225  
     226  /**< private >
     227   * string_check:
     228   *
     229   * @string: NULL-terminated string. Must not be empty
     230   *
     231   * Asserts that @string is present in the set
     232   */
     233  MODULE_EXPORT
     234  void
     235  string_check (const char *string)
     236  {
     237    if (string_find_index_ (string) >= sizeof (buffer))
     238      g_error ("String %s not present", string);
     239  }