Ondřej Hruška 4 years ago
commit 4412ab9f43
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 63
      .gitignore
  2. 6
      CMakeLists.txt
  3. 174
      main.c
  4. 72
      strlcat.c
  5. 55
      strlcat.h

63
.gitignore vendored

@ -0,0 +1,63 @@
*.swp
.lock*
.waf*
*.pyc
.project
.cproject
.settings
~*
pdebug*
*.tar*
*.log
packetlog.db
*.bin
*.dat
*.map
*~
*.bak
fsim
*.img
# ninja files
build.ninja
rules.ninja
.ninja_deps
.ninja_log
# generated by cmake
CMakeCache.txt
*.cmake
CMakeFiles
vcom
Makefile
*.cbp
*.a
.idea/
.DS_Store
build/
clion-build/
cmake-build-*/
CMakeLists.txt.user
# Visual Studio clutter
_ReSharper*
*.sdf
*.suo
*.dir
*.vcxproj*
*.sln
.vs
CMakeSettings.json
Win32
x64
Debug
Release
MinSizeRel
RelWithDebInfo
*.opensdf
*.out

@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.15)
project(a)
set(CMAKE_BUILD_TYPE Debug)
add_executable(a main.c strlcat.c)

174
main.c

@ -0,0 +1,174 @@
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include "strlcat.h"
int main () {
// Test argument checking
assert(0 == strlcpy(NULL, "", 10));
assert(0 == strlcpy("", NULL, 10));
assert(0 == strlcpy(NULL, NULL, 10));
assert(0 == strlncpy(NULL, "", 10, 10));
assert(0 == strlncpy("", NULL, 10, 10));
assert(0 == strlncpy(NULL, NULL, 10, 10));
assert(0 == strlcat(NULL, "", 10));
assert(0 == strlcat("", NULL, 10));
assert(0 == strlcat(NULL, NULL, 10));
assert(0 == strlncat(NULL, "", 10, 10));
assert(0 == strlncat("", NULL, 10, 10));
assert(0 == strlncat(NULL, NULL, 10, 10));
// strlcpy
{
char buf[5] = {0,1,2,3,4};
assert(9 == strlcpy(buf, "abcdefgh", 4));
assert(buf[0] == 'a');
assert(buf[1] == 'b');
assert(buf[2] == 'c');
assert(buf[3] == 0);
assert(buf[4] == 4);
}
{
char buf[5] = {0,1,2,3,4};
assert(3 == strlcpy(buf, "ab", 5));
assert(buf[0] == 'a');
assert(buf[1] == 'b');
assert(buf[2] == 0);
assert(buf[3] == 3);
}
{
char buf[5] = {5,4,3,2,1};
assert(7 == strlcpy(buf, "abcdef", 1));
assert(buf[0] == 0); // it puts the zero there
assert(buf[1] == 4);
}
// strlncpy
{
char buf[5] = {0,1,2,3,4};
assert(3 == strlncpy(buf, "abcdefgh", 4, 2));
assert(buf[0] == 'a');
assert(buf[1] == 'b');
assert(buf[2] == 0);
assert(buf[3] == 3);
}
{
char buf[5] = {0,1,2,3,4};
assert(5 == strlncpy(buf, "abcdefgh", 5, 4));
assert(buf[0] == 'a');
assert(buf[1] == 'b');
assert(buf[2] == 'c');
assert(buf[3] == 'd');
assert(buf[4] == 0);
}
{
char buf[5] = {5,4,3,2,1};
assert(2 == strlncpy(buf, "abcdef", 1, 1));
assert(buf[0] == 0); // it puts the zero there
assert(buf[1] == 4);
}
// strlcat
{
char buf[8] = {0,1,2,3,4,5,6,7};
assert(2 == strlcat(buf, "a", 8));
assert(buf[0] == 'a');
assert(buf[1] == 0);
assert(buf[2] == 2);
}
{
char buf[8] = {0,1,2,3,4,5,6,7};
assert(3 == strlcat(buf, "ab", 8));
assert(buf[0] == 'a');
assert(buf[1] == 'b');
assert(buf[2] == 0);
assert(buf[3] == 3);
assert(5 == strlcat(buf, "xx", 8));
assert(0==strcmp(buf,"abxx"));
assert(5 == strlcat(buf, "", 8)); // this just sets the terminator
assert(0==strcmp(buf,"abxx"));
assert(8 == strlcat(buf, "dog", 8));
assert(0==strcmp(buf,"abxxdog"));
assert(10 == strlcat(buf, "ff", 8));
assert(0==strcmp(buf,"abxxdog"));
}
{
char buf[5] = {5,4,3,2,1};
assert(7 == strlcat(buf, "abcdef", 1));
assert(buf[0] == 0); // it puts the zero there
assert(buf[1] == 4);
}
// strlncat
{
char buf[8] = {0,1,2,3,4,5,6,7};
assert(2 == strlncat(buf, "a", 8, 1));
assert(buf[0] == 'a');
assert(buf[1] == 0);
assert(buf[2] == 2);
}
{
char buf[8] = {0,1,2,3,4,5,6,7};
assert(2 == strlncat(buf, "a", 8, 50)); // larger n than string size
assert(buf[0] == 'a');
assert(buf[1] == 0);
assert(buf[2] == 2);
}
{
char buf[8] = {0,1,2,3,4,5,6,7};
assert(26 == strlncat(buf, "abcdefghijklmnopqrstuvwyx", 8, 50)); // larger n than string size & larger than capacity
assert(0==strcmp(buf, "abcdefg"));
}
{
char buf[8] = {0,1,2,3,4,5,6,7};
assert(5 == strlncat(buf, "abcd", 8, 50)); // larger n than string size & larger than capacity
assert(0==strcmp(buf, "abcd"));
assert(buf[4] == 0);
assert(buf[5] == 5);
}
{
char buf[8] = {0,1,2,3,4,5,6,7};
assert(3 == strlncat(buf, "abcdef", 8, 2));
assert(buf[0] == 'a');
assert(buf[1] == 'b');
assert(buf[2] == 0);
assert(buf[3] == 3);
assert(5 == strlncat(buf, "xxyyyyy", 8, 2));
assert(0==strcmp(buf,"abxx"));
assert(5 == strlncat(buf, "", 8, 100)); // this just sets the terminator
assert(0==strcmp(buf,"abxx"));
assert(5 == strlncat(buf, "", 8, 0));
assert(0==strcmp(buf,"abxx"));
assert(8 == strlncat(buf, "doggg", 8, 3));
assert(0==strcmp(buf,"abxxdog"));
assert(10 == strlncat(buf, "ffxxx", 8, 2));
assert(0==strcmp(buf,"abxxdog"));
}
{
char buf[5] = {5,4,3,2,1};
assert(2 == strlncat(buf, "abcdef", 1, 1));
assert(buf[0] == 0); // it puts the zero there
assert(buf[1] == 4);
}
// this is a test that asserts are evaluated
assert((printf("all ok\n"), 1));
return 0;
}

@ -0,0 +1,72 @@
#include <string.h>
#include <stddef.h>
size_t strlcat(char *__restrict__ dst, const char *__restrict__ src, size_t capacity)
{
if (!dst) { return 0; }
if (!src) { return 0; }
size_t used = strnlen(dst, capacity);
if (used >= capacity) { used = capacity - 1; }
size_t to_print = strlen(src);
// to_print does not include the terminator
const size_t needed = used + to_print + 1;
if (needed > capacity) {
to_print = capacity - used - 1;
}
memcpy(dst + used, src, to_print);
*(dst + used + to_print) = '\0';
return needed;
}
size_t strlncat(char *__restrict__ dst, const char *__restrict__ src, size_t capacity, size_t num)
{
if (!dst) { return 0; }
if (!src) { return 0; }
size_t used = strnlen(dst, capacity);
if (used >= capacity) { used = capacity - 1; }
size_t to_print = strlen(src);
if (to_print > num) {
to_print = num;
}
// to_print does not include the terminator
const size_t needed = used + to_print + 1;
if (needed > capacity) {
to_print = capacity - used - 1;
}
memcpy(dst + used, src, to_print);
*(dst + used + to_print) = '\0';
return needed;
}
size_t strlcpy(char *__restrict__ dst, const char *__restrict__ src, size_t capacity)
{
if (!dst) { return 0; }
if (!src) { return 0; }
size_t to_print = strlen(src);
// to_print does not include the terminator
const size_t needed = to_print + 1;
if (needed > capacity) {
to_print = capacity - 1;
}
memcpy(dst, src, to_print);
*(dst + to_print) = '\0';
return needed;
}
size_t strlncpy(char *__restrict__ dst, const char *__restrict__ src, size_t capacity, size_t num)
{
if (!dst) { return 0; }
if (!src) { return 0; }
size_t to_print = strlen(src);
if (to_print > num) {
to_print = num;
}
// to_print does not include the terminator
const size_t needed = to_print + 1;
if (needed > capacity) {
to_print = capacity - 1;
}
memcpy(dst, src, to_print);
*(dst + to_print) = '\0';
return needed;
}

@ -0,0 +1,55 @@
/**
* Strcat variant respecting buffer capacity.
* Function signatures based on libbsd.
*
* Created by Ondřej Hruška on 2020/09/19.
*/
#ifndef STRLCAT_H
#define STRLCAT_H
#include <stddef.h>
/**
* Append a zero-terminated to a zero-terminated buffer.
*
* @param[out] dst - destination buffer
* @param[in] src - source string
* @param[in] capacity - destination buffer capacity
* @return The buffer size needed. If > size, then data loss occurred. Returns 0 if invalid arguments were supplied.
*/
size_t strlcat(char *__restrict__ dst, const char *__restrict__ src, size_t capacity);
/**
* Append at most N characters of a zero-terminated string to a zero-terminated buffer.
*
* @param[out] dst - destination buffer
* @param[in] src - source string
* @param[in] capacity - destination buffer capacity
* @param[in] num - number of bytes to write
* @return The buffer size needed. If > size, then data loss occurred. Returns 0 if invalid arguments were supplied.
*/
size_t strlncat(char *__restrict__ dst, const char *__restrict__ src, size_t capacity, size_t num);
/**
* Copy a zero-terminated string to a zero-terminated buffer.
*
* @param[out] dst - destination buffer
* @param[in] src - source string
* @param[in] capacity - destination buffer capacity
* @return The buffer size needed. If > size, then data loss occurred. Returns 0 if invalid arguments were supplied.
*/
size_t strlcpy(char *__restrict__ dst, const char *__restrict__ src, size_t capacity);
/**
* Copy at most N characters of a zero-terminated string to a zero-terminated buffer.
*
* @param[out] dst - destination buffer
* @param[in] src - source string
* @param[in] capacity - destination buffer capacity
* @param[in] num - number of bytes to write
* @return The buffer size needed. If > size, then data loss occurred. Returns 0 if invalid arguments were supplied.
*/
size_t strlncpy(char *__restrict__ dst, const char *__restrict__ src, size_t capacity, size_t num);
#endif //STRLCAT_H
Loading…
Cancel
Save