| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344 |
- /*
- * SPDX-FileCopyrightText: 2013-2019 Tom G. Huang
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
- /*******************************************************************************
- * arg_dstr: Implements the dynamic string utilities
- *
- * This file is part of the argtable3 library.
- *
- * Copyright (C) 2013-2019 Tom G. Huang
- * <tomghuang@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of STEWART HEITMANN nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- ******************************************************************************/
- #include "argtable3.h"
- #ifndef ARG_AMALGAMATION
- #include "argtable3_private.h"
- #endif
- #include <stdarg.h>
- #include <stdlib.h>
- #include <string.h>
- #if defined(_MSC_VER)
- #pragma warning(push)
- #pragma warning(disable : 4996)
- #endif
- #define START_VSNBUFF 16
- /*
- * This dynamic string module is adapted from TclResult.c in the Tcl library.
- * Here is the copyright notice from the library:
- *
- * This software is copyrighted by the Regents of the University of
- * California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState
- * Corporation and other parties. The following terms apply to all files
- * associated with the software unless explicitly disclaimed in
- * individual files.
- *
- * The authors hereby grant permission to use, copy, modify, distribute,
- * and license this software and its documentation for any purpose, provided
- * that existing copyright notices are retained in all copies and that this
- * notice is included verbatim in any distributions. No written agreement,
- * license, or royalty fee is required for any of the authorized uses.
- * Modifications to this software may be copyrighted by their authors
- * and need not follow the licensing terms described here, provided that
- * the new terms are clearly indicated on the first page of each file where
- * they apply.
- *
- * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
- * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
- * DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
- * IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
- * NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
- * MODIFICATIONS.
- *
- * GOVERNMENT USE: If you are acquiring this software on behalf of the
- * U.S. government, the Government shall have only "Restricted Rights"
- * in the software and related documentation as defined in the Federal
- * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
- * are acquiring the software on behalf of the Department of Defense, the
- * software shall be classified as "Commercial Computer Software" and the
- * Government shall have only "Restricted Rights" as defined in Clause
- * 252.227-7014 (b) (3) of DFARs. Notwithstanding the foregoing, the
- * authors grant the U.S. Government and others acting in its behalf
- * permission to use and distribute the software in accordance with the
- * terms specified in this license.
- */
- typedef struct _internal_arg_dstr {
- char* data;
- arg_dstr_freefn* free_proc;
- char sbuf[ARG_DSTR_SIZE + 1];
- char* append_data;
- int append_data_size;
- int append_used;
- } _internal_arg_dstr_t;
- static void setup_append_buf(arg_dstr_t res, int newSpace);
- arg_dstr_t arg_dstr_create(void) {
- _internal_arg_dstr_t* h = (_internal_arg_dstr_t*)xmalloc(sizeof(_internal_arg_dstr_t));
- memset(h, 0, sizeof(_internal_arg_dstr_t));
- h->sbuf[0] = 0;
- h->data = h->sbuf;
- h->free_proc = ARG_DSTR_STATIC;
- return h;
- }
- void arg_dstr_destroy(arg_dstr_t ds) {
- if (ds == NULL)
- return;
- arg_dstr_reset(ds);
- xfree(ds);
- return;
- }
- void arg_dstr_set(arg_dstr_t ds, char* str, arg_dstr_freefn* free_proc) {
- int length;
- register arg_dstr_freefn* old_free_proc = ds->free_proc;
- char* old_result = ds->data;
- if (str == NULL) {
- ds->sbuf[0] = 0;
- ds->data = ds->sbuf;
- ds->free_proc = ARG_DSTR_STATIC;
- } else if (free_proc == ARG_DSTR_VOLATILE) {
- length = (int)strlen(str);
- if (length > ARG_DSTR_SIZE) {
- ds->data = (char*)xmalloc((unsigned)length + 1);
- ds->free_proc = ARG_DSTR_DYNAMIC;
- } else {
- ds->data = ds->sbuf;
- ds->free_proc = ARG_DSTR_STATIC;
- }
- strcpy(ds->data, str);
- } else {
- ds->data = str;
- ds->free_proc = free_proc;
- }
- /*
- * If the old result was dynamically-allocated, free it up. Do it here,
- * rather than at the beginning, in case the new result value was part of
- * the old result value.
- */
- if ((old_free_proc != 0) && (old_result != ds->data)) {
- if (old_free_proc == ARG_DSTR_DYNAMIC) {
- xfree(old_result);
- } else {
- (*old_free_proc)(old_result);
- }
- }
- if ((ds->append_data != NULL) && (ds->append_data_size > 0)) {
- xfree(ds->append_data);
- ds->append_data = NULL;
- ds->append_data_size = 0;
- }
- }
- char* arg_dstr_cstr(arg_dstr_t ds) /* Interpreter whose result to return. */
- {
- return ds->data;
- }
- void arg_dstr_cat(arg_dstr_t ds, const char* str) {
- setup_append_buf(ds, (int)strlen(str) + 1);
- memcpy(ds->data + strlen(ds->data), str, strlen(str));
- }
- void arg_dstr_catc(arg_dstr_t ds, char c) {
- setup_append_buf(ds, 2);
- memcpy(ds->data + strlen(ds->data), &c, 1);
- }
- /*
- * The logic of the `arg_dstr_catf` function is adapted from the `bformat`
- * function in The Better String Library by Paul Hsieh. Here is the copyright
- * notice from the library:
- *
- * Copyright (c) 2014, Paul Hsieh
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * * Neither the name of bstrlib nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- void arg_dstr_catf(arg_dstr_t ds, const char* fmt, ...) {
- va_list arglist;
- char* buff;
- int n, r;
- size_t slen;
- if (fmt == NULL)
- return;
- /* Since the length is not determinable beforehand, a search is
- performed using the truncating "vsnprintf" call (to avoid buffer
- overflows) on increasing potential sizes for the output result. */
- if ((n = (int)(2 * strlen(fmt))) < START_VSNBUFF)
- n = START_VSNBUFF;
- buff = (char*)xmalloc((size_t)(n + 2));
- memset(buff, 0, (size_t)(n + 2));
- for (;;) {
- va_start(arglist, fmt);
- r = vsnprintf(buff, (size_t)(n + 1), fmt, arglist);
- va_end(arglist);
- slen = strlen(buff);
- if (slen < (size_t)n)
- break;
- if (r > n)
- n = r;
- else
- n += n;
- xfree(buff);
- buff = (char*)xmalloc((size_t)(n + 2));
- memset(buff, 0, (size_t)(n + 2));
- }
- arg_dstr_cat(ds, buff);
- xfree(buff);
- }
- static void setup_append_buf(arg_dstr_t ds, int new_space) {
- int total_space;
- /*
- * Make the append buffer larger, if that's necessary, then copy the
- * data into the append buffer and make the append buffer the official
- * data.
- */
- if (ds->data != ds->append_data) {
- /*
- * If the buffer is too big, then free it up so we go back to a
- * smaller buffer. This avoids tying up memory forever after a large
- * operation.
- */
- if (ds->append_data_size > 500) {
- xfree(ds->append_data);
- ds->append_data = NULL;
- ds->append_data_size = 0;
- }
- ds->append_used = (int)strlen(ds->data);
- } else if (ds->data[ds->append_used] != 0) {
- /*
- * Most likely someone has modified a result created by
- * arg_dstr_cat et al. so that it has a different size. Just
- * recompute the size.
- */
- ds->append_used = (int)strlen(ds->data);
- }
- total_space = new_space + ds->append_used;
- if (total_space >= ds->append_data_size) {
- char* newbuf;
- if (total_space < 100) {
- total_space = 200;
- } else {
- total_space *= 2;
- }
- newbuf = (char*)xmalloc((unsigned)total_space);
- memset(newbuf, 0, (size_t)total_space);
- strcpy(newbuf, ds->data);
- if (ds->append_data != NULL) {
- xfree(ds->append_data);
- }
- ds->append_data = newbuf;
- ds->append_data_size = total_space;
- } else if (ds->data != ds->append_data) {
- strcpy(ds->append_data, ds->data);
- }
- arg_dstr_free(ds);
- ds->data = ds->append_data;
- }
- void arg_dstr_free(arg_dstr_t ds) {
- if (ds->free_proc != NULL) {
- if (ds->free_proc == ARG_DSTR_DYNAMIC) {
- xfree(ds->data);
- } else {
- (*ds->free_proc)(ds->data);
- }
- ds->free_proc = NULL;
- }
- }
- void arg_dstr_reset(arg_dstr_t ds) {
- arg_dstr_free(ds);
- if ((ds->append_data != NULL) && (ds->append_data_size > 0)) {
- xfree(ds->append_data);
- ds->append_data = NULL;
- ds->append_data_size = 0;
- }
- ds->data = ds->sbuf;
- ds->sbuf[0] = 0;
- }
- #if defined(_MSC_VER)
- #pragma warning(pop)
- #endif
|