Thread: [Libclc-developers] Some of the string functions
Status: Planning
Brought to you by:
augestad
|
From: Hallvard B F. <h.b...@us...> - 2003-03-24 19:07:48
|
Here are the string functions I have added. See the previously posted
doc for detailed descriptions.
clc_stpcpy - copy string and return pointer to end
/* $Id: clc_stpcpy.c,v 1.1 2003/03/22 09:17:33 augestad Exp $ */
#include <stddef.h>
#include "clc_assert.h"
#include "clc_string.h"
/* Copyright(c) 2003, Hallvard B. Furuseth. (h.b...@us...) */
char *clc_stpcpy(char *CLC_RESTRICT s1, const char *CLC_RESTRICT s2)
{
clc_assert_not_null(clc_stpcpy, s1);
clc_assert_not_null(clc_stpcpy, s2);
while ((*s1 = *s2++) != '\0')
s1++;
return s1;
}
clc_strendcpy - copy limited string and return pointer to end
/* $Id: clc_strendcpy.c,v 1.2 2003/03/23 09:55:11 hfuru Exp $ */
/*
* Copyright(c) 2003, Howard Chu <hy...@hi...>
*/
#include <stddef.h>
#include "clc_assert.h"
#include "clc_string.h"
char *
clc_strendcpy(char *dst, const char *CLC_RESTRICT src, const char *end)
{
clc_assert_arg(clc_strendcpy, dst != NULL && src != NULL && end != NULL);
if (dst < end) {
end--; /* room for terminating NUL */
while (dst < end && *src)
*dst++ = *src++;
*dst = '\0';
if (*src)
dst++; /* return end parameter if truncation */
}
return dst;
}
clc_stralloc - concatenate arguments, ending with (char*)0, to a new
malloced string
/* $Id: clc_stralloc.c,v 1.4 2003/03/22 14:34:21 hfuru Exp $ */
/*
* Copyright(c) 2003, Hallvard B. Furuseth <h.b...@us...>.
*/
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "clc_string.h"
char *clc_stralloc(const char *arg1, ...)
{
size_t len;
const char *arg;
char *ret, *end;
va_list ap;
int bad;
bad = 0;
len = 1;
va_start(ap, arg1);
for (arg = arg1; arg != (char *)0; arg = va_arg(ap, char *)) {
size_t arglen = strlen(arg);
len += arglen;
if(len < arglen) {
/* string length too large for size_t */
bad = 1;
break;
}
}
va_end(ap);
if(bad)
return NULL;
ret = malloc(len);
if(ret != NULL) {
end = ret;
*end = '\0';
va_start(ap, arg1);
for (arg = arg1; arg != (char *)0; arg = va_arg(ap, char *))
end = clc_stpcpy(end, arg);
va_end(ap);
}
return ret;
}
clc_strcasecmp - case-insensitive string compare
/* $Id: clc_strcasecmp.c,v 1.1 2003/03/23 17:13:02 hfuru Exp $ */
/*
* Copyright(c) 2003, Hallvard B. Furuseth <h.b...@us...>.
*/
#include <ctype.h>
#include "clc_assert.h"
#include "clc_string.h"
int
clc_strcasecmp(const char *s1, const char *s2)
{
for (;; s1++, s2++) {
int c1, c2;
c1 = tolower((unsigned char)*s1);
c2 = tolower((unsigned char)*s2);
if (c1 == '\0' || c1 != c2)
return c1 - c2;
}
}
clc_strcasecmp - case-insensitive string compare with size limit
/* $Id: clc_strncasecmp.c,v 1.1 2003/03/23 17:13:02 hfuru Exp $ */
/*
* Copyright(c) 2003, Hallvard B. Furuseth <h.b...@us...>.
*/
#include <ctype.h>
#include "clc_assert.h"
#include "clc_string.h"
int
clc_strncasecmp(const char *s1, const char *s2, size_t n)
{
for (; n--; s1++, s2++) {
int c1 = tolower((unsigned char)*s1);
int c2 = tolower((unsigned char)*s2);
if (c1 == '\0' || c1 != c2)
return c1 - c2;
}
return 0;
}
clc_strsep, clc_strtok_r - extract token from string, return token
/* $Id: clc_strsep.c,v 1.1 2003/03/22 12:19:29 hfuru Exp $ */
/*
* Copyright (C) 2003, Hallvard B. Furuseth <h.b...@us...>.
*/
#include <string.h>
#include "clc_string.h"
#include "clc_assert.h"
char *
clc_strsep(char **CLC_RESTRICT stringp, const char *CLC_RESTRICT delim)
{
char *str, *end;
clc_assert_arg(clc_strsep, delim != NULL);
clc_assert_arg(clc_strsep, stringp != NULL && *stringp != NULL);
str = *stringp + strspn(*stringp, delim);
if (*str == '\0') {
end = str;
str = NULL;
} else {
end = str + strcspn(str, delim);
if (*end != '\0')
*end++ = '\0';
}
*stringp = end;
return str;
}
char *
clc_strtok_r(char *str, const char *CLC_RESTRICT delim, char **tracker)
{
clc_assert_arg(clc_strtok_r, delim != NULL);
clc_assert_arg(clc_strtok_r, tracker != NULL);
clc_assert_arg(clc_strtok_r, str != NULL || *tracker != NULL);
if (str != NULL)
*tracker = str;
return clc_strsep(tracker, delim);
}
--
Hallvard
|
|
From: <bo...@me...> - 2003-03-24 21:29:49
|
Hallvard B Furuseth wrote:
> Here are the string functions I have added. See the previously posted
> doc for detailed descriptions.
>
> /* Copyright(c) 2003, Hallvard B. Furuseth. (h.b...@us...) */
> char *clc_stpcpy(char *CLC_RESTRICT s1, const char *CLC_RESTRICT s2)
> {
> clc_assert_not_null(clc_stpcpy, s1);
> clc_assert_not_null(clc_stpcpy, s2);
A general question: Given the fact that the asserts are for the libclc
*user* only, how about an assert like this one?
clc_assert_arg(clc_stpcpy, s1 != s2);
I just use you code as an example here.
>
> char *
> clc_strendcpy(char *dst, const char *CLC_RESTRICT src, const char *end)
> {
> clc_assert_arg(clc_strendcpy, dst != NULL && src != NULL && end != NULL);
If I was the user of libclc, I'd prefer to get the exact name of the
invalid argument. This kind of assert forces me to check up to three
variables. The line is also longer than 72 characters.
> if (dst < end) {
> end--; /* room for terminating NUL */
> while (dst < end && *src)
> *dst++ = *src++;
> *dst = '\0';
> if (*src)
> dst++; /* return end parameter if truncation */
> }
> return dst;
> }
>
> char *clc_stralloc(const char *arg1, ...)
> {
> size_t len;
> const char *arg;
> char *ret, *end;
> va_list ap;
> int bad;
>
> bad = 0;
> len = 1;
How about "int bad = 0;" on one line instead?
>
> int
> clc_strcasecmp(const char *s1, const char *s2)
> {
Asserts?
>
> int
> clc_strncasecmp(const char *s1, const char *s2, size_t n)
> {
Asserts?
> char *
> clc_strsep(char **CLC_RESTRICT stringp, const char *CLC_RESTRICT delim)
> {
> char *str, *end;
> clc_assert_arg(clc_strsep, delim != NULL);
clc_assert_not_null()?
>
> char *
> clc_strtok_r(char *str, const char *CLC_RESTRICT delim, char **tracker)
> {
> clc_assert_arg(clc_strtok_r, delim != NULL);
> clc_assert_arg(clc_strtok_r, tracker != NULL);
clc_assert_not_null()?
Looks very good! Just a few asserts away from beeing production ready. ;-)
--
boa
libclc home: http://libclc.sourceforge.net
|
|
From: Hallvard B F. <h.b...@us...> - 2003-03-25 11:30:59
|
Bj=F8rn Augestad writes:
>Hallvard B Furuseth wrote:
>=20
>> char *clc_stpcpy(char *CLC_RESTRICT s1, const char *CLC_RESTRICT s2)
>> {
>> clc_assert_not_null(clc_stpcpy, s1);
>> clc_assert_not_null(clc_stpcpy, s2);
>=20
> A general question: Given the fact that the asserts are for the libclc=20
> *user* only, how about an assert like this one?
>
> clc_assert_arg(clc_stpcpy, s1 !=3D s2);
>
> I just use you code as an example here.
In this case I don't think so, because that condition is incomplete.
The full test is something like !(s1 <=3D s2 && s2 <=3D s1+strlen(s1)), and
I don't like that either because of the slowdown from strlen. Some
people say one should only use the debug version of libclc while testing
code, and in that case assert slowdown may not be important, but there
are people (e.g. FSF, I think) who release code with asserts turned on
so that they can get good error reports from their users.
I've fixed the other asserts like you said.
>> char *clc_stralloc(const char *arg1, ...)
>> {
>> size_t len;
>> const char *arg;
>> char *ret, *end;
>> va_list ap;
>> int bad;
>>=20
>> bad =3D 0;
>> len =3D 1;
>=20
> How about "int bad =3D 0;" on one line instead?
Well, I just wrote it in what I hope will be the libclc style. I like
initializations to be close to the block which uses the values when
possible, which would usually have to be separate statements since there
will usually be asserts between the declarations and the rest of the
code. Doesn't matter since there are no asserts here of course, so I
could have moved the len and bad declarations down and added
initializers. Feel free to do so yourself if you want.
--=20
Hallvard
|