From 454c1fdf661d38fd143da73a0ae9cf97ab5c2d6e Mon Sep 17 00:00:00 2001 From: Jason King Date: Sun, 16 Sep 2018 01:10:39 +0000 Subject: OS-7858 Allow a range of bytes to be removed from a custr --- usr/src/lib/libcustr/common/custr.c | 75 ++++++++++++++++++++++ usr/src/lib/libcustr/common/libcustr.h | 48 +++++++++++++- usr/src/lib/libcustr/common/mapfile-vers | 6 +- usr/src/test/util-tests/runfiles/default.run | 5 +- usr/src/test/util-tests/tests/Makefile | 2 +- usr/src/test/util-tests/tests/libcustr/Makefile | 50 +++++++++++++++ .../test/util-tests/tests/libcustr/custr_remove.c | 73 +++++++++++++++++++++ .../test/util-tests/tests/libcustr/custr_trunc.c | 64 ++++++++++++++++++ 8 files changed, 319 insertions(+), 4 deletions(-) create mode 100644 usr/src/test/util-tests/tests/libcustr/Makefile create mode 100644 usr/src/test/util-tests/tests/libcustr/custr_remove.c create mode 100644 usr/src/test/util-tests/tests/libcustr/custr_trunc.c diff --git a/usr/src/lib/libcustr/common/custr.c b/usr/src/lib/libcustr/common/custr.c index 6d3a003e6b..c321df5029 100644 --- a/usr/src/lib/libcustr/common/custr.c +++ b/usr/src/lib/libcustr/common/custr.c @@ -85,6 +85,81 @@ custr_reset(custr_t *cus) 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 || idx + len > 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) { diff --git a/usr/src/lib/libcustr/common/libcustr.h b/usr/src/lib/libcustr/common/libcustr.h index 8fe5fee1b7..f8f15db07b 100644 --- a/usr/src/lib/libcustr/common/libcustr.h +++ b/usr/src/lib/libcustr/common/libcustr.h @@ -10,7 +10,7 @@ */ /* - * Copyright 2019, Joyent, Inc. + * Copyright 2019 Joyent, Inc. */ #ifndef _LIBCUSTR_H @@ -141,6 +141,52 @@ size_t custr_len(custr_t *); */ 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 diff --git a/usr/src/lib/libcustr/common/mapfile-vers b/usr/src/lib/libcustr/common/mapfile-vers index f94636b6f5..53b94164ad 100644 --- a/usr/src/lib/libcustr/common/mapfile-vers +++ b/usr/src/lib/libcustr/common/mapfile-vers @@ -10,7 +10,7 @@ # # -# Copyright 2019, Joyent, Inc. +# Copyright 2019 Joyent, Inc. # # @@ -42,7 +42,11 @@ SYMBOL_VERSION ILLUMOSprivate { custr_cstr; custr_free; custr_len; + custr_remove; custr_reset; + custr_rremove; + custr_rtrunc; + custr_trunc; custr_xalloc; custr_xalloc_buf; local: diff --git a/usr/src/test/util-tests/runfiles/default.run b/usr/src/test/util-tests/runfiles/default.run index f8569b1423..c124a9c2ba 100644 --- a/usr/src/test/util-tests/runfiles/default.run +++ b/usr/src/test/util-tests/runfiles/default.run @@ -13,7 +13,7 @@ # Copyright (c) 2012 by Delphix. All rights reserved. # Copyright 2014 Garrett D'Amore # Copyright 2014 Nexenta Systems, Inc. All rights reserved. -# Copyright 2019, Joyent, Inc. +# Copyright 2019 Joyent, Inc. # [DEFAULT] @@ -60,3 +60,6 @@ tests = ['afl-fast', 'gcc-libstdc++', 'llvm-stdcxxabi'] [/opt/util-tests/tests/ctf] pre = precheck tests = [ 'ctftest' ] + +[/opt/util-tests/tests/libcustr] +tests = ['custr_remove', 'custr_trunc'] diff --git a/usr/src/test/util-tests/tests/Makefile b/usr/src/test/util-tests/tests/Makefile index cb2d3028da..cb687ecdf6 100644 --- a/usr/src/test/util-tests/tests/Makefile +++ b/usr/src/test/util-tests/tests/Makefile @@ -19,6 +19,6 @@ SUBDIRS = date dis dladm iconv libnvpair_json libsff printf xargs grep_xpg4 SUBDIRS += demangle mergeq workq chown -SUBDIRS += bunyan awk smbios libjedec ctf +SUBDIRS += bunyan awk smbios libjedec ctf libcustr include $(SRC)/test/Makefile.com diff --git a/usr/src/test/util-tests/tests/libcustr/Makefile b/usr/src/test/util-tests/tests/libcustr/Makefile new file mode 100644 index 0000000000..3aa4c5c76a --- /dev/null +++ b/usr/src/test/util-tests/tests/libcustr/Makefile @@ -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) diff --git a/usr/src/test/util-tests/tests/libcustr/custr_remove.c b/usr/src/test/util-tests/tests/libcustr/custr_remove.c new file mode 100644 index 0000000000..e58ab8c22a --- /dev/null +++ b/usr/src/test/util-tests/tests/libcustr/custr_remove.c @@ -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 +#include +#include +#include +#include +#include + +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); + + 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); +} diff --git a/usr/src/test/util-tests/tests/libcustr/custr_trunc.c b/usr/src/test/util-tests/tests/libcustr/custr_trunc.c new file mode 100644 index 0000000000..6825512ad9 --- /dev/null +++ b/usr/src/test/util-tests/tests/libcustr/custr_trunc.c @@ -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 +#include +#include +#include +#include +#include +#include + +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); + + 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); +} -- cgit v1.2.3