]> Savannah Git Hosting - gnulib.git/commitdiff
mbs_endswith: New module.
authorBruno Haible <bruno@clisp.org>
Fri, 3 Jan 2025 12:32:32 +0000 (13:32 +0100)
committerBruno Haible <bruno@clisp.org>
Fri, 3 Jan 2025 12:32:32 +0000 (13:32 +0100)
* lib/string.in.h (mbs_endswith): New declaration.
* lib/mbs_endswith.c: New file.
* m4/string_h.m4 (gl_STRING_H_REQUIRE_DEFAULTS): Initialize
GNULIB_MBS_ENDSWITH.
* modules/string-h (Makefile.am): Substitute GNULIB_MBS_ENDSWITH.
* modules/mbs_endswith: New file.

ChangeLog
lib/mbs_endswith.c [new file with mode: 0644]
lib/string.in.h
m4/string_h.m4
modules/mbs_endswith [new file with mode: 0644]
modules/string-h

index a7b87e70610645de719240bdbd905507f3091bcd..4dc577daf5b93ecd182e2c343c88b4f096007c57 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2025-01-03  Bruno Haible  <bruno@clisp.org>
+
+       mbs_endswith: New module.
+       * lib/string.in.h (mbs_endswith): New declaration.
+       * lib/mbs_endswith.c: New file.
+       * m4/string_h.m4 (gl_STRING_H_REQUIRE_DEFAULTS): Initialize
+       GNULIB_MBS_ENDSWITH.
+       * modules/string-h (Makefile.am): Substitute GNULIB_MBS_ENDSWITH.
+       * modules/mbs_endswith: New file.
+
 2025-01-03  Bruno Haible  <bruno@clisp.org>
 
        mbs_startswith: New module.
diff --git a/lib/mbs_endswith.c b/lib/mbs_endswith.c
new file mode 100644 (file)
index 0000000..5007a44
--- /dev/null
@@ -0,0 +1,74 @@
+/* mbs_endswith function.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation, either version 3 of the
+   License, or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2025.  */
+
+#include "config.h"
+
+/* Specification.  */
+#include <string.h>
+
+#include "mbiter.h"
+
+#include <stdlib.h>
+
+int
+mbs_endswith (const char *string, const char *suffix)
+{
+  if ((unsigned char) suffix[0] < 0x30)
+    /* Some knowledge about the possible multibyte encodings:
+
+       Encoding    First byte of character    Which of these can occur
+                                              as second or later byte?
+
+        EUC-JP     0x00..0x7F, 0x8E..0xFE     0xA1..0xFE
+        EUC-KR     0x00..0x7F, 0xA1..0xFD     0xA1..0xFD
+        GB2312     0x00..0x7F, 0xA1..0xF7     0xA1..0xF7
+        EUC-TW     0x00..0x7F, 0x8E..0xFD     0xA1..0xFD
+        BIG5       0x00..0x7F, 0xA1..0xF9     0x40..0x7E, 0xA1..0xF9
+        GB18030    0x00..0x7F, 0x81..0xFE     0x30..0x39, 0x40..0x7E, 0x81..0xFE
+        SJIS       0x00..0x7F, 0x81..0xF9     0x40..0x7E, 0x81..0xF9
+        UTF-8      0x00..0x7F, 0xC2..0xF7     none
+
+       Therefore, if the first byte of SUFFIX is < 0x30, it cannot occur as
+       second or later byte, and therefore it is OK to do a bytewise search.  */
+    return str_endswith (string, suffix);
+
+  /* Here, suffix is not empty.  */
+
+  size_t nbytes = strlen (string);
+  if (nbytes >= strlen (suffix))
+    {
+      size_t len = mbslen (string);
+      size_t n = mbslen (suffix);
+      if (len >= n)
+        {
+          mbi_iterator_t iter;
+          mbi_init (iter, string, nbytes);
+          /* Advance past (len - n) multibyte characters.  */
+          for (; len > n; len--)
+            {
+              if (!mbi_avail (iter))
+                abort ();
+              mbi_advance (iter);
+            }
+          if (!mbi_avail (iter))
+            abort ();
+          return strcmp (mbi_cur_ptr (iter), suffix) == 0;
+        }
+    }
+  return 0;
+}
index ce5b493d7174583d55222891f9029b26238badcd..6b9e342a1a2fb881234fb5ce7e996823b0c6cba1 100644 (file)
@@ -1327,6 +1327,16 @@ _GL_EXTERN_C int mbs_startswith (const char *string, const char *prefix)
 # define mbs_startswith str_startswith
 #endif
 
+#if @GNULIB_MBS_ENDSWITH@
+/* Returns true if STRING ends with SUFFIX.
+   Returns false otherwise.
+   Unlike str_endswith(), this function works correctly in multibyte locales.
+ */
+_GL_EXTERN_C int mbs_endswith (const char *string, const char *suffix)
+     _GL_ATTRIBUTE_PURE
+     _GL_ARG_NONNULL ((1, 2));
+#endif
+
 /* Map any int, typically from errno, into an error message.  */
 #if @GNULIB_STRERROR@
 # if @REPLACE_STRERROR@
index a2c8536f38e3110389b8fc6af2f3fa6a99c6e7fd..d0a676081143341012d0c1461eacea0a53d1f36c 100644 (file)
@@ -1,5 +1,5 @@
 # string_h.m4
-# serial 42
+# serial 43
 dnl Copyright (C) 2007-2025 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -87,6 +87,7 @@ AC_DEFUN([gl_STRING_H_REQUIRE_DEFAULTS],
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSSEP])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSTOK_R])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBS_STARTSWITH])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBS_ENDSWITH])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRERROR])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRERROR_R])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRERRORNAME_NP])
diff --git a/modules/mbs_endswith b/modules/mbs_endswith
new file mode 100644 (file)
index 0000000..19ead99
--- /dev/null
@@ -0,0 +1,26 @@
+Description:
+mbs_endswith() function: test whether a multibyte string ends with a given suffix.
+
+Files:
+lib/mbs_endswith.c
+
+Depends-on:
+string-h
+str_endswith
+mbslen
+mbiter
+
+configure.ac:
+gl_STRING_MODULE_INDICATOR([mbs_endswith])
+
+Makefile.am:
+lib_SOURCES += mbs_endswith.c
+
+Include:
+<string.h>
+
+License:
+LGPL
+
+Maintainer:
+all
index 1114bcf9eb4db8ca31a6458355a7f9c4fd1898a7..4f9c20542491f58ee0a357a2fa0df7db9b3eb897 100644 (file)
@@ -51,6 +51,7 @@ string.h: string.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
              -e 's/@''GNULIB_MBSSPN''@/$(GNULIB_MBSSPN)/g' \
              -e 's/@''GNULIB_MBSSEP''@/$(GNULIB_MBSSEP)/g' \
              -e 's/@''GNULIB_MBSTOK_R''@/$(GNULIB_MBSTOK_R)/g' \
+             -e 's/@''GNULIB_MBS_ENDSWITH''@/$(GNULIB_MBS_ENDSWITH)/g' \
              -e 's/@''GNULIB_MBS_STARTSWITH''@/$(GNULIB_MBS_STARTSWITH)/g' \
              -e 's/@''GNULIB_MEMCHR''@/$(GNULIB_MEMCHR)/g' \
              -e 's/@''GNULIB_MEMMEM''@/$(GNULIB_MEMMEM)/g' \