1 /**
2  * \file rpmio/rpmstring.c
3  */
4 
5 #include "system.h"
6 
7 #include <stdarg.h>
8 #include <stdio.h>
9 
10 #include <rpm/rpmstring.h>
11 #include "debug.h"
12 
13 
rstrcasecmp(const char * s1,const char * s2)14 int rstrcasecmp(const char * s1, const char * s2)
15 {
16   const char * p1 = s1;
17   const char * p2 = s2;
18   char c1, c2;
19 
20   if (p1 == p2)
21     return 0;
22 
23   do
24     {
25       c1 = rtolower (*p1++);
26       c2 = rtolower (*p2++);
27       if (c1 == '\0')
28         break;
29     }
30   while (c1 == c2);
31 
32   return (int)(c1 - c2);
33 }
34 
rstrncasecmp(const char * s1,const char * s2,size_t n)35 int rstrncasecmp(const char *s1, const char *s2, size_t n)
36 {
37   const char * p1 = s1;
38   const char * p2 = s2;
39   char c1, c2;
40 
41   if (p1 == p2 || n == 0)
42     return 0;
43 
44   do
45     {
46       c1 = rtolower (*p1++);
47       c2 = rtolower (*p2++);
48       if (c1 == '\0' || c1 != c2)
49 	break;
50     } while (--n > 0);
51 
52   return (int)(c1 - c2);
53 }
54 
rvasprintf(char ** strp,const char * fmt,va_list ap)55 int rvasprintf(char **strp, const char *fmt, va_list ap)
56 {
57     int n;
58     char * p = NULL;
59     va_list aq;
60 
61     if (strp == NULL)
62 	return -1;
63 
64     va_copy(aq, ap);
65     n = vsnprintf(NULL, 0, fmt, aq);
66     va_end(aq);
67 
68     if (n >= -1) {
69 	size_t nb = n + 1;
70 	p = xmalloc(nb);
71 	va_copy(aq, ap);
72         n = vsnprintf(p, nb, fmt, aq);
73 	va_end(aq);
74     }
75     *strp = p;
76     return n;
77 }
78 
rasprintf(char ** strp,const char * fmt,...)79 int rasprintf(char **strp, const char *fmt, ...)
80 {
81     int n;
82     va_list ap;
83 
84     va_start(ap, fmt);
85     n = rvasprintf(strp, fmt, ap);
86     va_end(ap);
87 
88     return n;
89 }
90 
91 /*
92  * Concatenate two strings with dynamically (re)allocated
93  * memory what prevents static buffer overflows by design.
94  * *dest is reallocated to the size of strings to concatenate.
95  *
96  * Note:
97  * 1) char *buf = rstrcat(NULL,"string"); is the same like rstrcat(&buf,"string");
98  * 2) rstrcat(&buf,NULL) returns buf
99  * 3) rstrcat(NULL,NULL) returns NULL
100  * 4) *dest and src can overlap
101  */
rstrcat(char ** dest,const char * src)102 char *rstrcat(char **dest, const char *src)
103 {
104     if ( src == NULL ) {
105 	return dest != NULL ? *dest : NULL;
106     }
107 
108     if ( dest == NULL ) {
109 	return xstrdup(src);
110     }
111 
112     {
113 	size_t dest_size = *dest != NULL ? strlen(*dest) : 0;
114 	size_t src_size = strlen(src);
115 
116 	*dest = xrealloc(*dest, dest_size+src_size+1);		/* include '\0' */
117 	memmove(&(*dest)[dest_size], src, src_size+1);
118     }
119 
120     return *dest;
121 }
122 
123 /*
124  * Concatenate strings with dynamically (re)allocated
125  * memory what prevents static buffer overflows by design.
126  * *dest is reallocated to the size of strings to concatenate.
127  * List of strings has to be NULL terminated.
128  *
129  * Note:
130  * 1) char *buf = rstrscat(NULL,"string",NULL); is the same like rstrscat(&buf,"string",NULL);
131  * 2) rstrscat(&buf,NULL) returns buf
132  * 3) rstrscat(NULL,NULL) returns NULL
133  * 4) *dest and argument strings can overlap
134  */
rstrscat(char ** dest,const char * arg,...)135 char *rstrscat(char **dest, const char *arg, ...)
136 {
137     va_list ap;
138     size_t arg_size, dst_size;
139     const char *s;
140     char *dst, *p;
141 
142     dst = dest ? *dest : NULL;
143 
144     if ( arg == NULL ) {
145         return dst;
146     }
147 
148     va_start(ap, arg);
149     for (arg_size=0, s=arg; s; s = va_arg(ap, const char *))
150         arg_size += strlen(s);
151     va_end(ap);
152 
153     dst_size = dst ? strlen(dst) : 0;
154     dst = xrealloc(dst, dst_size+arg_size+1);    /* include '\0' */
155     p = &dst[dst_size];
156 
157     va_start(ap, arg);
158     for (s = arg; s; s = va_arg(ap, const char *)) {
159         size_t size = strlen(s);
160         memmove(p, s, size);
161         p += size;
162     }
163     va_end(ap);
164     *p = '\0';
165 
166     if ( dest ) {
167         *dest = dst;
168     }
169 
170     return dst;
171 }
172 
173 /*
174  * Adapted from OpenBSD, strlcpy() originally developed by
175  * Todd C. Miller <Todd.Miller@courtesan.com>
176  */
rstrlcpy(char * dest,const char * src,size_t n)177 size_t rstrlcpy(char *dest, const char *src, size_t n)
178 {
179     char *d = dest;
180     const char *s = src;
181     size_t len = n;
182 
183     /* Copy as many bytes as will fit */
184     if (len != 0) {
185 	while (--len != 0) {
186 	    if ((*d++ = *s++) == '\0')
187 		break;
188 	}
189     }
190 
191     /* Not enough room in dst, add NUL and traverse rest of src */
192     if (len == 0) {
193 	if (n != 0)
194 	    *d = '\0'; /* NUL-terminate dst */
195 	while (*s++)
196 	    ;
197     }
198 
199     return s - src - 1; /* count does not include NUL */
200 }
201