cscg24-guacamole

CSCG 2024 Challenge 'Guacamole Mashup'
git clone https://git.sinitax.com/sinitax/cscg24-guacamole
Log | Files | Refs | sfeed.txt

string.c (5037B)


      1/*
      2 * Licensed to the Apache Software Foundation (ASF) under one
      3 * or more contributor license agreements.  See the NOTICE file
      4 * distributed with this work for additional information
      5 * regarding copyright ownership.  The ASF licenses this file
      6 * to you under the Apache License, Version 2.0 (the
      7 * "License"); you may not use this file except in compliance
      8 * with the License.  You may obtain a copy of the License at
      9 *
     10 *   http://www.apache.org/licenses/LICENSE-2.0
     11 *
     12 * Unless required by applicable law or agreed to in writing,
     13 * software distributed under the License is distributed on an
     14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     15 * KIND, either express or implied.  See the License for the
     16 * specific language governing permissions and limitations
     17 * under the License.
     18 */
     19
     20#include "config.h"
     21
     22#include "guacamole/mem.h"
     23
     24#include <stddef.h>
     25#include <string.h>
     26
     27/**
     28 * Returns the space remaining in a buffer assuming that the given number of
     29 * bytes have already been written. If the number of bytes exceeds the size
     30 * of the buffer, zero is returned.
     31 *
     32 * @param n
     33 *     The size of the buffer in bytes.
     34 *
     35 * @param length
     36 *     The number of bytes which have been written to the buffer so far. If
     37 *     the routine writing the bytes will automatically truncate its writes,
     38 *     this value may exceed the size of the buffer.
     39 *
     40 * @return
     41 *     The number of bytes remaining in the buffer. This value will always
     42 *     be non-negative. If the number of bytes written already exceeds the
     43 *     size of the buffer, zero will be returned.
     44 */
     45#define REMAINING(n, length) (((n) < (length)) ? 0 : ((n) - (length)))
     46
     47size_t guac_strlcpy(char* restrict dest, const char* restrict src, size_t n) {
     48
     49#ifdef HAVE_STRLCPY
     50    return strlcpy(dest, src, n);
     51#else
     52    /* Calculate actual length of desired string */
     53    size_t length = strlen(src);
     54
     55    /* Copy nothing if there is no space */
     56    if (n == 0)
     57        return length;
     58
     59    /* Calculate length of the string which will be copied */
     60    size_t copy_length = length;
     61    if (copy_length >= n)
     62        copy_length = n - 1;
     63
     64    /* Copy only as much of string as possible, manually adding a null
     65     * terminator */
     66    memcpy(dest, src, copy_length);
     67    dest[copy_length] = '\0';
     68
     69    /* Return the overall length of the desired string */
     70    return length;
     71#endif
     72
     73}
     74
     75size_t guac_strlcat(char* restrict dest, const char* restrict src, size_t n) {
     76
     77#ifdef HAVE_STRLCPY
     78    return strlcat(dest, src, n);
     79#else
     80    size_t length = strnlen(dest, n);
     81    return length + guac_strlcpy(dest + length, src, REMAINING(n, length));
     82#endif
     83
     84}
     85
     86char* guac_strnstr(const char *haystack, const char *needle, size_t len) {
     87
     88#ifdef HAVE_STRNSTR
     89    return strnstr(haystack, needle, len);
     90#else
     91    char* chr;
     92    size_t nlen = strlen(needle), off = 0;
     93
     94    /* Follow documented API: return haystack if needle is the empty string. */
     95    if (nlen == 0)
     96        return (char *)haystack;
     97
     98    /* Use memchr to find candidates. It might be optimized in asm. */
     99    while (off < len && NULL != (chr = memchr(haystack + off, needle[0], len - off))) {
    100        /* chr is guaranteed to be in bounds of and >= haystack. */
    101        off = chr - haystack;
    102        /* If needle would go beyond provided len, it doesn't exist in haystack. */
    103        if (off + nlen > len)
    104            return NULL;
    105        /* Now that we know we have at least nlen bytes, compare them. */
    106        if (!memcmp(chr, needle, nlen))
    107            return chr;
    108        /* Make sure we make progress. */
    109        off += 1;
    110    }
    111
    112    /* memchr ran out of candidates, needle wasn't found. */
    113    return NULL;
    114#endif
    115
    116}
    117
    118char* guac_strdup(const char* str) {
    119
    120    /* Return NULL if no string provided */
    121    if (str == NULL)
    122        return NULL;
    123
    124    /* Do not attempt to duplicate if the length is somehow magically so
    125     * obscenely large that it will not be possible to add a null terminator */
    126    size_t length;
    127    if (guac_mem_ckd_add(&length, strlen(str), 1))
    128        return NULL;
    129
    130    /* Otherwise just copy to a new string in same manner as strdup() */
    131    void* new_str = guac_mem_alloc(length);
    132    if (new_str != NULL)
    133        memcpy(new_str, str, length);
    134
    135    return new_str;
    136
    137}
    138
    139size_t guac_strljoin(char* restrict dest, const char* restrict const* elements,
    140        int nmemb, const char* restrict delim, size_t n) {
    141
    142    size_t length = 0;
    143    const char* restrict const* current = elements;
    144
    145    /* If no elements are provided, nothing to do but ensure the destination
    146     * buffer is null terminated */
    147    if (nmemb <= 0)
    148        return guac_strlcpy(dest, "", n);
    149
    150    /* Initialize destination buffer with first element */
    151    length += guac_strlcpy(dest, *current, n);
    152
    153    /* Copy all remaining elements, separated by delimiter */
    154    for (current++; nmemb > 1; current++, nmemb--) {
    155        length += guac_strlcat(dest + length, delim, REMAINING(n, length));
    156        length += guac_strlcat(dest + length, *current, REMAINING(n, length));
    157    }
    158
    159    return length;
    160
    161}
    162