changeset 19376:50a678a2c678

12178 Allow bytes to be removed from a custr Reviewed by: Toomas Soome <tsoome@me.com> Reviewed by: Andy Fiddaman <andy@omniosce.org> Approved by: Gordon Ross <gwr@nexenta.com>
author Jason King <jason.king@joyent.com>
date Thu, 09 Jan 2020 10:59:44 -0600
parents 0ec870e4a0af
children ce42a2836d9d
files usr/src/lib/libcustr/common/custr.c usr/src/lib/libcustr/common/libcustr.h usr/src/lib/libcustr/common/mapfile-vers usr/src/pkg/manifests/system-test-utiltest.mf usr/src/test/util-tests/runfiles/default.run usr/src/test/util-tests/tests/Makefile usr/src/test/util-tests/tests/libcustr/Makefile usr/src/test/util-tests/tests/libcustr/custr_remove.c usr/src/test/util-tests/tests/libcustr/custr_trunc.c
diffstat 9 files changed, 324 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/lib/libcustr/common/custr.c	Wed Dec 18 08:05:59 2019 -0800
+++ b/usr/src/lib/libcustr/common/custr.c	Thu Jan 09 10:59:44 2020 -0600
@@ -14,7 +14,7 @@
  */
 
 /*
- * Copyright 2019 Joyent, Inc.
+ * Copyright 2020 Joyent, Inc.
  */
 
 #include <stdlib.h>
@@ -85,6 +85,81 @@
 	cus->cus_data[0] = '\0';
 }
 
+int
+custr_remove(custr_t *cus, size_t idx, size_t len)
+{
+	size_t endidx = idx + len;
+
+	/*
+	 * Once gcc4 is dropped as a shadow compiler, we can migrate to
+	 * using builtins for the overflow check.
+	 */
+	if (endidx < idx || endidx < len) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (idx >= cus->cus_strlen || endidx > cus->cus_strlen) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (len == 0)
+		return (0);
+
+	/* The +1 will include the terminating NUL in the move */
+	(void) memmove(cus->cus_data + idx, cus->cus_data + endidx,
+	    cus->cus_strlen - endidx + 1);
+	cus->cus_strlen -= len;
+
+	/* The result should be NUL */
+	VERIFY0(cus->cus_data[cus->cus_strlen]);
+	return (0);
+}
+
+int
+custr_rremove(custr_t *cus, size_t ridx, size_t len)
+{
+	size_t idx;
+
+	if (ridx >= cus->cus_strlen) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	idx = cus->cus_strlen - ridx - 1;
+	return (custr_remove(cus, idx, len));
+}
+
+int
+custr_trunc(custr_t *cus, size_t idx)
+{
+	if (idx >= cus->cus_strlen) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	cus->cus_data[idx] = '\0';
+	cus->cus_strlen = idx;
+	return (0);
+}
+
+int
+custr_rtrunc(custr_t *cus, size_t ridx)
+{
+	size_t idx;
+
+	if (ridx >= cus->cus_strlen) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	idx = cus->cus_strlen - ridx - 1;
+	cus->cus_data[idx] = '\0';
+	cus->cus_strlen = idx;
+	return (0);
+}
+
 size_t
 custr_len(custr_t *cus)
 {
--- a/usr/src/lib/libcustr/common/libcustr.h	Wed Dec 18 08:05:59 2019 -0800
+++ b/usr/src/lib/libcustr/common/libcustr.h	Thu Jan 09 10:59:44 2020 -0600
@@ -10,7 +10,7 @@
  */
 
 /*
- * Copyright 2019, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
  */
 
 #ifndef _LIBCUSTR_H
@@ -142,6 +142,52 @@
 void custr_reset(custr_t *);
 
 /*
+ * custr_remove(cus, idx, len)
+ *
+ * Remove len bytes from cus, starting at idx.
+ *
+ * Returns 0 on success or -1 on failure.  On failure, errno will be set to:
+ *	EINVAL	Either the idx or len parameter is invalid
+ *
+ */
+int custr_remove(custr_t *, size_t, size_t);
+
+/*
+ * custr_rremove(cus, idx, len)
+ *
+ * Remove len bytes from cus, starting at idx relative to the end of cus.
+ * That is, 0 = last byte of cus, 1 = second to last byte of cus, ...).
+ * The direction of removal is always towards the end of the string.  I.e.
+ * 'custr_rremove(cus, 1, 2)' removes the last two bytes of cus.
+ *
+ * Returns 0 on success or -1 on failure.  On failure, errno will be set to:
+ *	EINVAL	Either the idx or len parameter is invalid
+ *
+ */
+int custr_rremove(custr_t *, size_t, size_t);
+
+/*
+ * custr_trunc(cus, idx)
+ *
+ * Truncate cus starting at idx.
+ *
+ * Returns 0 on success or -1 on failure.  On failure, errno is set to:
+ *	EINVAL	The idx value was invalid.
+ */
+int custr_trunc(custr_t *, size_t);
+
+/*
+ * custr_rtrunc(cus, idx)
+ *
+ * Truncate cus starting at idx relative to the end of cus (similar to how
+ * the idx paramter is treated with custr_rremove()).
+ *
+ * Returns 0 on success or -1 on failure.  On failure, errno is set to:
+ *	EINVAL	The idx value was invalid.
+ */
+int custr_rtrunc(custr_t *, size_t);
+
+/*
  * Retrieve a const pointer to a NUL-terminated string version of the contents
  * of the dynamic string.  Storage for this string should not be freed, and
  * the pointer will be invalidated by any mutations to the dynamic string.
--- a/usr/src/lib/libcustr/common/mapfile-vers	Wed Dec 18 08:05:59 2019 -0800
+++ b/usr/src/lib/libcustr/common/mapfile-vers	Thu Jan 09 10:59:44 2020 -0600
@@ -10,7 +10,7 @@
 #
 
 #
-# Copyright 2019, Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
 #
 
 #
@@ -42,7 +42,11 @@
 	custr_cstr;
 	custr_free;
 	custr_len;
+	custr_remove;
 	custr_reset;
+	custr_rremove;
+	custr_rtrunc;
+	custr_trunc;
 	custr_xalloc;
 	custr_xalloc_buf;
     local:
--- a/usr/src/pkg/manifests/system-test-utiltest.mf	Wed Dec 18 08:05:59 2019 -0800
+++ b/usr/src/pkg/manifests/system-test-utiltest.mf	Thu Jan 09 10:59:44 2020 -0600
@@ -13,9 +13,8 @@
 # Copyright (c) 2012 by Delphix. All rights reserved.
 # Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved.
 # Copyright 2014 Nexenta Systems, Inc. All rights reserved.
-# Copyright 2019, Joyent, Inc.
+# Copyright 2020 Joyent, Inc.
 # Copyright 2017 Jason King.
-# Copyright 2018, Joyent, Inc.
 # Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
 #
 
@@ -56,6 +55,7 @@
 dir path=opt/util-tests/tests/files/make_a/b
 dir path=opt/util-tests/tests/files/make_a/c
 dir path=opt/util-tests/tests/files/make_l
+dir path=opt/util-tests/tests/libcustr
 dir path=opt/util-tests/tests/libnvpair_json
 dir path=opt/util-tests/tests/libsff
 dir path=opt/util-tests/tests/mergeq
@@ -1423,6 +1423,8 @@
 file path=opt/util-tests/tests/files/testnl mode=0444
 file path=opt/util-tests/tests/grep_test mode=0555
 file path=opt/util-tests/tests/iconv_test mode=0555
+file path=opt/util-tests/tests/libcustr/custr_remove mode=0555
+file path=opt/util-tests/tests/libcustr/custr_trunc mode=0555
 file path=opt/util-tests/tests/libjedec_test mode=0555
 file path=opt/util-tests/tests/libnvpair_json/json_00_blank mode=0555
 file path=opt/util-tests/tests/libnvpair_json/json_01_boolean mode=0555
--- a/usr/src/test/util-tests/runfiles/default.run	Wed Dec 18 08:05:59 2019 -0800
+++ b/usr/src/test/util-tests/runfiles/default.run	Thu Jan 09 10:59:44 2020 -0600
@@ -70,3 +70,6 @@
 [/opt/util-tests/tests/ctf]
 pre = precheck
 tests = [ 'ctftest' ]
+
+[/opt/util-tests/tests/libcustr]
+tests = ['custr_remove', 'custr_trunc']
--- a/usr/src/test/util-tests/tests/Makefile	Wed Dec 18 08:05:59 2019 -0800
+++ b/usr/src/test/util-tests/tests/Makefile	Thu Jan 09 10:59:44 2020 -0600
@@ -14,11 +14,12 @@
 # Copyright 2014 Garrett D'Amore <garrett@damore.org>
 # Copyright 2014 Nexenta Systems, Inc. All rights reserved.
 # Copyright 2017 Jason King
-# Copyright 2019 Joyent, Inc.
+# Copyright 2020 Joyent, Inc.
 # Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
 #
 
 SUBDIRS = date dis dladm iconv libnvpair_json libsff printf xargs grep_xpg4
 SUBDIRS += demangle mergeq workq chown ctf smbios libjedec awk make sleep
+SUBDIRS += libcustr
 
 include $(SRC)/test/Makefile.com
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/test/util-tests/tests/libcustr/Makefile	Thu Jan 09 10:59:44 2020 -0600
@@ -0,0 +1,50 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2019 Joyent, Inc.
+#
+
+include $(SRC)/Makefile.master
+
+ROOTOPTPKG = $(ROOT)/opt/util-tests
+TESTDIR = $(ROOTOPTPKG)/tests/libcustr
+
+PROGS = custr_remove custr_trunc
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/test/Makefile.com
+
+CMDS = $(PROGS:%=$(TESTDIR)/%)
+$(CMDS) := FILEMODE = 0555
+
+LDLIBS += -lcustr
+
+all: $(PROGS)
+
+install: all $(CMDS) $(OUTFILES)
+
+clobber: clean
+	-$(RM) $(PROGS)
+
+clean:
+
+$(CMDS): $(TESTDIR) $(PROG)
+
+$(TESTDIR):
+	$(INS.dir)
+
+$(TESTDIR)/%: %
+	$(INS.file)
+
+%: %.c
+	$(LINK.c) -o $@ $< $(LDLIBS)
+	$(POST_PROCESS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/test/util-tests/tests/libcustr/custr_remove.c	Thu Jan 09 10:59:44 2020 -0600
@@ -0,0 +1,73 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+#include <errno.h>
+#include <libcustr.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/debug.h>
+
+static void
+expect(const char *var, custr_t *cu, const char *str, const char *file,
+    size_t line)
+{
+	if (strcmp(custr_cstr(cu), str) == 0)
+		return;
+
+	char msgbuf[256];
+
+	(void) snprintf(msgbuf, sizeof (msgbuf), "%s == '%s' ('%s' == '%s')",
+	    var, str, custr_cstr(cu), str);
+
+	(void) assfail(msgbuf, file, line);
+}
+
+#define	EXPECT(_cu, _str) expect(#_cu, _cu, _str, __FILE__, __LINE__)
+#define	FAIL(_expr, _ev)		\
+	VERIFY3S(_expr, ==, -1);	\
+	VERIFY3S(errno, ==, (_ev))
+
+int
+main(void)
+{
+	custr_t *cu;
+
+	VERIFY0(custr_alloc(&cu));
+
+	VERIFY0(custr_append(cu, "12345"));
+	EXPECT(cu, "12345");
+
+	FAIL(custr_remove(cu, 6, 2), EINVAL);
+	FAIL(custr_remove(cu, 2, 10), EINVAL);
+	FAIL(custr_rremove(cu, 6, 2), EINVAL);
+	FAIL(custr_rremove(cu, 2, 10), EINVAL);
+
+	VERIFY0(custr_remove(cu, 0, 1));
+	EXPECT(cu, "2345");
+	VERIFY0(custr_rremove(cu, 1, 2));
+	EXPECT(cu, "23");
+
+	VERIFY0(custr_append(cu, "456"));
+	EXPECT(cu, "23456");
+
+	VERIFY0(custr_remove(cu, 1, 2));
+	EXPECT(cu, "256");
+
+	VERIFY0(custr_rremove(cu, 1, 2));
+	EXPECT(cu, "2");
+
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/test/util-tests/tests/libcustr/custr_trunc.c	Thu Jan 09 10:59:44 2020 -0600
@@ -0,0 +1,64 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+#include <errno.h>
+#include <libcustr.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/debug.h>
+
+static void
+expect(const char *var, custr_t *cu, const char *str, const char *file,
+    size_t line)
+{
+	if (strcmp(custr_cstr(cu), str) == 0)
+		return;
+
+	char msgbuf[256];
+
+	(void) snprintf(msgbuf, sizeof (msgbuf), "%s == '%s' ('%s' == '%s')",
+	    var, str, custr_cstr(cu), str);
+
+	(void) assfail(msgbuf, file, line);
+}
+
+#define	EXPECT(_cu, _str) expect(#_cu, _cu, _str, __FILE__, __LINE__)
+#define	FAIL(_expr, _ev)		\
+	VERIFY3S(_expr, ==, -1);	\
+	VERIFY3S(errno, ==, (_ev))
+
+int
+main(void)
+{
+	custr_t *cu;
+
+	VERIFY0(custr_alloc(&cu));
+
+	VERIFY0(custr_append(cu, "12345"));
+	EXPECT(cu, "12345");
+
+	FAIL(custr_trunc(cu, 6), EINVAL);
+	FAIL(custr_rtrunc(cu, 10), EINVAL);
+
+	VERIFY0(custr_trunc(cu, 3));
+	EXPECT(cu, "123");
+
+	VERIFY0(custr_rtrunc(cu, 1));
+	EXPECT(cu, "1");
+
+	return (0);
+}