2000-08-28 03:27:03 +08:00
|
|
|
/**
|
2007-11-23 14:11:42 +08:00
|
|
|
* \file rpmio/rpmstring.c
|
2000-08-28 03:27:03 +08:00
|
|
|
*/
|
|
|
|
|
1998-07-26 05:00:26 +08:00
|
|
|
#include "system.h"
|
1997-05-07 23:07:50 +08:00
|
|
|
|
2008-03-18 16:17:03 +08:00
|
|
|
#include <stdarg.h>
|
|
|
|
|
2007-12-08 20:02:32 +08:00
|
|
|
#include <rpm/rpmstring.h>
|
2000-12-13 04:03:45 +08:00
|
|
|
#include "debug.h"
|
1995-12-14 00:01:36 +08:00
|
|
|
|
|
|
|
#define BUF_CHUNK 1024
|
|
|
|
|
2001-05-06 03:28:32 +08:00
|
|
|
struct StringBufRec {
|
2002-04-13 09:28:20 +08:00
|
|
|
char *buf;
|
|
|
|
char *tail; /* Points to first "free" char */
|
2001-05-06 03:28:32 +08:00
|
|
|
int allocated;
|
|
|
|
int free;
|
|
|
|
};
|
|
|
|
|
2007-11-23 14:21:23 +08:00
|
|
|
char * stripTrailingChar(char * s, char c)
|
|
|
|
{
|
|
|
|
char * t;
|
|
|
|
for (t = s + strlen(s) - 1; *t == c && t >= s; t--)
|
|
|
|
*t = '\0';
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2007-12-14 17:38:20 +08:00
|
|
|
char ** splitString(const char * str, size_t length, char sep)
|
2007-11-23 14:21:23 +08:00
|
|
|
{
|
|
|
|
const char * source;
|
|
|
|
char * s, * dest;
|
|
|
|
char ** list;
|
|
|
|
int i;
|
|
|
|
int fields;
|
|
|
|
|
|
|
|
s = xmalloc(length + 1);
|
|
|
|
|
|
|
|
fields = 1;
|
|
|
|
for (source = str, dest = s, i = 0; i < length; i++, source++, dest++) {
|
|
|
|
*dest = *source;
|
|
|
|
if (*dest == sep) fields++;
|
|
|
|
}
|
|
|
|
|
|
|
|
*dest = '\0';
|
|
|
|
|
|
|
|
list = xmalloc(sizeof(*list) * (fields + 1));
|
|
|
|
|
|
|
|
dest = s;
|
|
|
|
list[0] = dest;
|
|
|
|
i = 1;
|
|
|
|
while (i < fields) {
|
|
|
|
if (*dest == sep) {
|
|
|
|
list[i++] = dest + 1;
|
|
|
|
*dest = 0;
|
|
|
|
}
|
|
|
|
dest++;
|
|
|
|
}
|
|
|
|
|
|
|
|
list[i] = NULL;
|
|
|
|
|
|
|
|
/* FIX: list[i] is NULL */
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
void freeSplitString(char ** list)
|
|
|
|
{
|
|
|
|
list[0] = _free(list[0]);
|
|
|
|
list = _free(list);
|
|
|
|
}
|
|
|
|
|
1995-12-14 00:01:36 +08:00
|
|
|
StringBuf newStringBuf(void)
|
|
|
|
{
|
2001-10-16 22:58:57 +08:00
|
|
|
StringBuf sb = xmalloc(sizeof(*sb));
|
1995-12-14 00:01:36 +08:00
|
|
|
|
1999-09-21 11:22:53 +08:00
|
|
|
sb->free = sb->allocated = BUF_CHUNK;
|
|
|
|
sb->buf = xcalloc(sb->allocated, sizeof(*sb->buf));
|
1995-12-14 00:01:36 +08:00
|
|
|
sb->buf[0] = '\0';
|
|
|
|
sb->tail = sb->buf;
|
|
|
|
|
|
|
|
return sb;
|
|
|
|
}
|
|
|
|
|
2001-05-06 03:28:32 +08:00
|
|
|
StringBuf freeStringBuf(StringBuf sb)
|
1995-12-14 00:01:36 +08:00
|
|
|
{
|
2001-05-06 03:28:32 +08:00
|
|
|
if (sb) {
|
|
|
|
sb->buf = _free(sb->buf);
|
|
|
|
sb = _free(sb);
|
1997-10-01 04:23:20 +08:00
|
|
|
}
|
2001-05-06 03:28:32 +08:00
|
|
|
return sb;
|
1995-12-14 00:01:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void truncStringBuf(StringBuf sb)
|
|
|
|
{
|
|
|
|
sb->buf[0] = '\0';
|
|
|
|
sb->tail = sb->buf;
|
|
|
|
sb->free = sb->allocated;
|
|
|
|
}
|
|
|
|
|
1996-07-03 03:16:06 +08:00
|
|
|
void stripTrailingBlanksStringBuf(StringBuf sb)
|
|
|
|
{
|
|
|
|
while (sb->free != sb->allocated) {
|
2008-03-18 15:10:13 +08:00
|
|
|
if (! risspace(*(sb->tail - 1)))
|
1996-07-03 03:16:06 +08:00
|
|
|
break;
|
|
|
|
sb->free++;
|
|
|
|
sb->tail--;
|
|
|
|
}
|
|
|
|
sb->tail[0] = '\0';
|
|
|
|
}
|
|
|
|
|
2001-05-06 03:28:32 +08:00
|
|
|
char * getStringBuf(StringBuf sb)
|
1995-12-14 00:01:36 +08:00
|
|
|
{
|
|
|
|
return sb->buf;
|
|
|
|
}
|
|
|
|
|
1999-01-06 07:13:56 +08:00
|
|
|
void appendStringBufAux(StringBuf sb, const char *s, int nl)
|
1995-12-14 00:01:36 +08:00
|
|
|
{
|
|
|
|
int l;
|
|
|
|
|
|
|
|
l = strlen(s);
|
|
|
|
/* If free == l there is no room for NULL terminator! */
|
1996-02-21 06:25:21 +08:00
|
|
|
while ((l + nl + 1) > sb->free) {
|
1995-12-14 00:01:36 +08:00
|
|
|
sb->allocated += BUF_CHUNK;
|
|
|
|
sb->free += BUF_CHUNK;
|
1999-09-21 11:22:53 +08:00
|
|
|
sb->buf = xrealloc(sb->buf, sb->allocated);
|
1995-12-14 00:01:36 +08:00
|
|
|
sb->tail = sb->buf + (sb->allocated - sb->free);
|
|
|
|
}
|
|
|
|
|
2007-09-12 01:07:39 +08:00
|
|
|
/* FIX: shrug */
|
1995-12-14 00:01:36 +08:00
|
|
|
strcpy(sb->tail, s);
|
|
|
|
sb->tail += l;
|
|
|
|
sb->free -= l;
|
|
|
|
if (nl) {
|
|
|
|
sb->tail[0] = '\n';
|
|
|
|
sb->tail[1] = '\0';
|
|
|
|
sb->tail++;
|
|
|
|
sb->free--;
|
|
|
|
}
|
|
|
|
}
|
2008-03-18 14:55:05 +08:00
|
|
|
|
2008-03-18 15:10:13 +08:00
|
|
|
int rstrcasecmp(const char * s1, const char * s2)
|
2008-03-18 14:55:05 +08:00
|
|
|
{
|
|
|
|
const char * p1 = s1;
|
|
|
|
const char * p2 = s2;
|
|
|
|
char c1, c2;
|
|
|
|
|
|
|
|
if (p1 == p2)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
2008-03-18 15:10:13 +08:00
|
|
|
c1 = rtolower (*p1++);
|
|
|
|
c2 = rtolower (*p2++);
|
2008-03-18 14:55:05 +08:00
|
|
|
if (c1 == '\0')
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
while (c1 == c2);
|
|
|
|
|
|
|
|
return (int)(c1 - c2);
|
|
|
|
}
|
|
|
|
|
2008-03-18 15:10:13 +08:00
|
|
|
int rstrncasecmp(const char *s1, const char *s2, size_t n)
|
2008-03-18 14:55:05 +08:00
|
|
|
{
|
|
|
|
const char * p1 = s1;
|
|
|
|
const char * p2 = s2;
|
|
|
|
char c1, c2;
|
|
|
|
|
|
|
|
if (p1 == p2 || n == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
2008-03-18 15:10:13 +08:00
|
|
|
c1 = rtolower (*p1++);
|
|
|
|
c2 = rtolower (*p2++);
|
2008-03-18 14:55:05 +08:00
|
|
|
if (c1 == '\0' || c1 != c2)
|
|
|
|
break;
|
|
|
|
} while (--n > 0);
|
|
|
|
|
|
|
|
return (int)(c1 - c2);
|
|
|
|
}
|
2008-03-18 16:17:03 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Simple and stupid asprintf() clone.
|
|
|
|
* FIXME: write to work with non-C99 vsnprintf or check for one in configure.
|
|
|
|
*/
|
|
|
|
int rasprintf(char **strp, const char *fmt, ...)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
va_list ap;
|
|
|
|
char * p = NULL;
|
|
|
|
|
|
|
|
if (strp == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
n = vsnprintf(NULL, 0, fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
if (n >= -1) {
|
|
|
|
size_t nb = n + 1;
|
|
|
|
p = xmalloc(nb);
|
|
|
|
va_start(ap, fmt);
|
2008-03-18 19:22:15 +08:00
|
|
|
n = vsnprintf(p, nb, fmt, ap);
|
2008-03-18 16:17:03 +08:00
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
*strp = p;
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2008-04-15 22:30:58 +08:00
|
|
|
/*
|
2008-04-17 14:57:43 +08:00
|
|
|
* Concatenate two strings with dynamically (re)allocated
|
2008-04-15 22:30:58 +08:00
|
|
|
* memory what prevents static buffer overflows by design.
|
|
|
|
* *dest is reallocated to the size of strings to concatenate.
|
|
|
|
*
|
|
|
|
* Note:
|
|
|
|
* 1) char *buf = rstrcat(NULL,"string"); is the same like rstrcat(&buf,"string");
|
|
|
|
* 2) rstrcat(&buf,NULL) returns buf
|
|
|
|
* 3) rstrcat(NULL,NULL) returns NULL
|
|
|
|
* 4) *dest and src can overlap
|
|
|
|
*/
|
|
|
|
char *rstrcat(char **dest, const char *src)
|
|
|
|
{
|
|
|
|
if ( src == NULL ) {
|
|
|
|
return dest != NULL ? *dest : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( dest == NULL ) {
|
|
|
|
return xstrdup(src);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
size_t dest_size = *dest != NULL ? strlen(*dest) : 0;
|
|
|
|
size_t src_size = strlen(src);
|
|
|
|
|
|
|
|
*dest = xrealloc(*dest, dest_size+src_size+1); /* include '\0' */
|
|
|
|
memmove(&(*dest)[dest_size], src, src_size+1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return *dest;
|
|
|
|
}
|
|
|
|
|
2008-04-17 14:57:43 +08:00
|
|
|
/*
|
|
|
|
* Concatenate strings with dynamically (re)allocated
|
|
|
|
* memory what prevents static buffer overflows by design.
|
|
|
|
* *dest is reallocated to the size of strings to concatenate.
|
|
|
|
* List of strings has to be NULL terminated.
|
|
|
|
*
|
|
|
|
* Note:
|
|
|
|
* 1) char *buf = rstrscat(NULL,"string",NULL); is the same like rstrscat(&buf,"string",NULL);
|
|
|
|
* 2) rstrscat(&buf,NULL) returns buf
|
|
|
|
* 3) rstrscat(NULL,NULL) returns NULL
|
|
|
|
* 4) *dest and argument strings can overlap
|
|
|
|
*/
|
|
|
|
char *rstrscat(char **dest, const char *arg, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
size_t arg_size, dst_size;
|
|
|
|
const char *s;
|
|
|
|
char *dst, *p;
|
|
|
|
|
|
|
|
dst = dest ? *dest : NULL;
|
|
|
|
|
|
|
|
if ( arg == NULL ) {
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
va_start(ap, arg);
|
|
|
|
for (arg_size=0, s=arg; s; s = va_arg(ap, const char *))
|
|
|
|
arg_size += strlen(s);
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
dst_size = dst ? strlen(dst) : 0;
|
|
|
|
dst = realloc(dst, dst_size+arg_size+1); /* include '\0' */
|
|
|
|
p = &dst[dst_size];
|
|
|
|
|
|
|
|
va_start(ap, arg);
|
|
|
|
for (s = arg; s; s = va_arg(ap, const char *)) {
|
|
|
|
size_t size = strlen(s);
|
|
|
|
memmove(p, s, size);
|
|
|
|
p += size;
|
|
|
|
}
|
|
|
|
*p = '\0';
|
|
|
|
|
|
|
|
if ( dest ) {
|
|
|
|
*dest = dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|