rcx

miscellaneous C library
git clone git://git.rr3.xyz/rcx
Log | Files | Refs | README | LICENSE

str.c (2799B)


      1 #define _ISOC99_SOURCE /* vsnprintf */
      2 #include <errno.h>
      3 #include <stdio.h>
      4 #include <string.h>
      5 
      6 #include "alloc.h"
      7 #include "debug.h"
      8 #include "log.h"
      9 #include "rcx.h"
     10 #include "str.h"
     11 
     12 /* TODO: e-versions of every function that can fail */
     13 
     14 static char *
     15 r_str_vcat(char *buf, usize len, va_list args) {
     16 	ASSERT(buf || len == 0);
     17 
     18 	char *s;
     19 	usize need = 1; /* Null terminator */
     20 
     21 	va_list args2;
     22 	va_copy(args2, args);
     23 	while ((s = va_arg(args2, char*))) {
     24 		usize slen = strlen(s);
     25 		if (slen > USIZE_MAX - need) {
     26 			va_end(args2);
     27 			errno = EOVERFLOW;
     28 			return 0;
     29 		}
     30 		need += slen;
     31 	}
     32 	va_end(args2);
     33 
     34 	if (buf && len < need) {
     35 		errno = ERANGE;
     36 		return 0;
     37 	} else if (!buf) {
     38 		buf = r_alloc(need);
     39 		if (!buf)
     40 			return 0;
     41 	}
     42 
     43 	char *b = buf;
     44 	while ((s = va_arg(args, char*))) {
     45 		while (*s)
     46 			*b++ = *s++;
     47 	}
     48 	*b = '\0';
     49 
     50 	return buf;
     51 }
     52 
     53 char *
     54 r_str_dup(char *s) {
     55 	char *dup = r_alloc(strlen(s) + 1);
     56 	if (!dup) return 0;
     57 	strcpy(dup, s);
     58 	return dup;
     59 }
     60 
     61 char *
     62 r_str_edup(char *s) {
     63 	char *dup = r_str_dup(s);
     64 	if (!dup) r_fatalf("allocation failure");
     65 	return dup;
     66 }
     67 
     68 char *
     69 r_str_cat(char *buf, usize len, ...) {
     70 	va_list args;
     71 	va_start(args, len);
     72 	char *ret = r_str_vcat(buf, len, args);
     73 	va_end(args);
     74 	return ret;
     75 }
     76 
     77 char *
     78 r_str_ecat(char *buf, usize len, ...) {
     79 	va_list args;
     80 	va_start(args, len);
     81 	char *ret = r_str_vcat(buf, len, args);
     82 	va_end(args);
     83 	if (!ret)
     84 		r_fatalf("r_str_ecat: %s", strerror(errno));
     85 	return ret;
     86 }
     87 
     88 bool
     89 r_str_starts_with(char *s, char *sub) {
     90 	return !strncmp(s, sub, strlen(sub));
     91 }
     92 
     93 bool
     94 r_str_ends_with(char *s, char *sub) {
     95 	usize slen = strlen(s);
     96 	usize sublen = strlen(sub);
     97 	return slen >= sublen && !strcmp(s + slen - sublen, sub);
     98 }
     99 
    100 usize
    101 r_str_count(char *s, char *sub) {
    102 	usize n = 0;
    103 	usize sublen = strlen(sub);
    104 	while ((s = strstr(s, sub))) {
    105 		n++;
    106 		s += sublen;
    107 	}
    108 	return n;
    109 }
    110 
    111 usize
    112 r_str_split(char ***fields, char *s, char *sep, usize n) {
    113 	ASSERT(strcmp(sep, ""), "separator must be nonempty");
    114 
    115 	if (n == 0) {
    116 		n = r_str_count(s, sep) + 1;
    117 		if (!(*fields = r_allocn(n, sizeof **fields)))
    118 			return 0;
    119 	}
    120 
    121 	usize seplen = strlen(sep);
    122 	usize i = 0;
    123 	while (i < n - 1) {
    124 		char *t = strstr(s, sep);
    125 		if (!t) break;
    126 		(*fields)[i++] = s;
    127 		memset(t, 0, seplen);
    128 		s = t + seplen;
    129 	}
    130 	(*fields)[i++] = s;
    131 
    132 	return i;
    133 }
    134 
    135 int
    136 r_vaprintf(char **s, const char *fmt, va_list args) {
    137 	va_list args2;
    138 	va_copy(args2, args);
    139 	int len = vsnprintf(0, 0, fmt, args2);
    140 	va_end(args2);
    141 	if (len < 0)
    142 		return len;
    143 
    144 	char *buf = r_alloc(len+1);
    145 	if (!buf)
    146 		return -1;
    147 
    148 	int ret = vsnprintf(buf, len+1, fmt, args);
    149 	if (ret < 0)
    150 		free(buf);
    151 	else
    152 		*s = buf;
    153 
    154 	return ret;
    155 }
    156 
    157 int
    158 r_aprintf(char **s, const char *fmt, ...) {
    159 	va_list args;
    160 	va_start(args, fmt);
    161 	int ret = r_vaprintf(s, fmt, args);
    162 	va_end(args);
    163 	return ret;
    164 }