source: project/release/4/readline/tags/4.1.3/trunk/foreign.c @ 34923

Last change on this file since 34923 was 34923, checked in by Alexej Magura, 3 years ago

releasing version 4.1.3: heres to a build that hopefully isnt broken

File size: 7.4 KB
Line 
1/****
2Copyright 2015 Alexej Magura
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15****/
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <stdbool.h>
20#include <string.h>
21#include <limits.h>
22#include <stdarg.h>
23
24#include "foreign.h"
25#include "musthaves.h"
26
27char *concat(const char *s1, ...)
28{
29        va_list args;
30        const char *s;
31        char *p, *result;
32        unsigned long l, m, n;
33
34        m = n = strlen(s1);
35        va_start(args, s1);
36        while ((s = va_arg(args, char *))) {
37                l = strlen(s);
38                if ((m += l) < l) break;
39        }
40        va_end(args);
41        if (s || m >= INT_MAX) return NULL;
42
43#if defined(__cplusplus)
44        result = (char *)malloc(m + 1);
45#else
46        result = malloc(m + 1);
47#endif
48        if (!result) return NULL;
49
50        memcpy(p = result, s1, n);
51        p += n;
52        va_start(args, s1);
53        while ((s = va_arg(args, char *))) {
54                l = strlen(s);
55                if ((n += l) < l || n > m) break;
56                memcpy(p, s, l);
57                p += l;
58        }
59        va_end(args);
60        if (s || m != n || p != result + n) {
61                free(result);
62                return NULL;
63        }
64
65        *p = '\0';
66        return result;
67}
68
69/* unlike `concat', which returns a
70 * new pointer that must then be copied
71 * or acted upon in some meaningfully meaningless
72 * manner, `catl' returns the number of bytes belonging
73 * to `buf', which could _NOT_ be filled, always copying
74 * no more than `bufsiz` of data into `buf'
75 *
76 * If the return value is an integral value, which
77 * we'll call `y', that is less than 0,
78 * then the resulting catenation has been truncated by `!y'
79 * many bytes.  Similarlly, if a positive value is returned:
80 * `y' many bytes is how much of `buf', which was _NOT_ used.
81 *
82 * XXX A failure is indicated by a return value _equal to
83 * the destination buffers size_, which may make errors somewhat
84 * harder to spot! */
85size_t concatl(char *dst, size_t sz, const char *s1, ...)
86{
87     va_list args;
88     const char *s = NULL;
89     char *p, *tmp;
90     unsigned long ldx, mdx, ndx;
91     size_t used = 0;
92
93     mdx = ndx = strlen(s1);
94     va_start(args, s1);
95     while ((s = va_arg(args, char *))) {
96          ldx = strlen(s);
97          if ((mdx += ldx) < ldx) break;
98     }
99     va_end(args);
100     if (s || mdx >= INT_MAX) return sz;
101
102#if defined(__cplusplus)
103     tmp = (char *)malloc(mdx + 1);
104#else
105     tmp = malloc(mdx + 1);
106#endif
107     if (!tmp) return sz;
108     bzero(tmp, mdx + 1);
109     bzero(dst, mdx + 1);
110
111     p = tmp;
112     p = mempcpy(p, (char *)s1, ndx);
113
114     used += ndx;
115     RD_DBG("p: `%s`\n", p);
116     RD_DBG("used: %lu\n", used - 0);
117
118     va_start(args, s1);
119     while ((s = va_arg(args, char *))) {
120          ldx = strlen(s);
121          if ((ndx += ldx) < ldx || ndx > mdx) break;
122          p = mempcpy(p, (char *)s, ldx);
123          used += ldx;
124     }
125     va_end(args);
126     if (s || mdx != ndx || p != tmp + ndx) {
127          free(tmp);
128          return sz;
129     }
130
131     RD_DBG("tmp: `%s'\n", tmp);
132     p = mempcpy(dst, tmp, (used > sz ? sz : used));
133     free(tmp);
134     *p = '\0';
135     ++used;
136
137     RD_DBG("dst: `%s'\n", dst);
138     RD_DBG("*p: `%c'\n", *p);
139     RD_DBG("*--p: `%c'\n", cpeek(p, dst, 0));
140     RD_DBG("strlen(dst): %lu\n", strlen(dst));
141     RD_DBG("used#2: %lu\n", used - 0);
142
143     return (used > sz ? 0 : sz - used);
144}
145
146/* concatm is a little different:
147 * unlike `concatl' or `concat', concatm _moves_ memory: that is, the destination
148 * pointer can be passed as an argument. */
149size_t concatm(char *dst, size_t sz, const char *s1, ...)
150{
151     va_list args;
152     const char *s = NULL;
153     char *p, *tmp;
154     unsigned long ldx, mdx, ndx;
155     size_t used = 0;
156
157     mdx = ndx = strlen(s1);
158     va_start(args, s1);
159     while ((s = va_arg(args, char *))) {
160          ldx = strlen(s);
161          if ((mdx += ldx) < ldx) break;
162     }
163     va_end(args);
164     if (s || mdx >= INT_MAX) return sz;
165
166#if defined(__cplusplus)
167     tmp = (char *)malloc(mdx + 1);
168#else
169     tmp = malloc(mdx + 1);
170#endif
171     if (!tmp) return sz;
172     bzero(tmp, mdx + 1);
173
174     p = tmp;
175     p = mempcpy(p, (char *)s1, ndx);
176
177     used += ndx;
178     RD_DBG("p: `%s`\n", p);
179     RD_DBG("used: %lu\n", used - 0);
180
181     va_start(args, s1);
182     while ((s = va_arg(args, char *))) {
183          ldx = strlen(s);
184          if ((ndx += ldx) < ldx || ndx > mdx) break;
185          p = mempcpy(p, (char *)s, ldx);
186          used += ldx;
187     }
188     va_end(args);
189     if (s || mdx != ndx || p != tmp + ndx) {
190          free(tmp);
191          return sz;
192     }
193     RD_DBG("tmp: `%s'\n", tmp);
194#if defined(mempmove) && 0
195     p = mempmove(dst, tmp, (used > sz ? sz : used));
196#else
197     memmove(dst, tmp, (used > sz ? sz : used));
198     p = &dst[(used > sz ? sz : used)];
199#endif
200     free(tmp);
201     *p = '\0';
202     ++used;
203
204     RD_DBG("dst: `%s'\n", dst);
205     RD_DBG("*p: `%c'\n", *p);
206     RD_DBG("*--p: `%c'\n", cpeek(p, dst, 0));
207     RD_DBG("strlen(dst): %lu\n", strlen(dst));
208     RD_DBG("used#2: %lu\n", used - 0);
209
210     return (used > sz ? 0 : sz - used);
211}
212
213char cpeek(const char *c, const char *s, const short fwd)
214{
215     if (fwd > 0) {
216          if (*c == '\0'
217# if defined(_GNU_SOURCE)
218              || c == strchr(s, '\0') - 1
219# else
220              || c == &s[strlen(s)]
221# endif
222               )
223               return *c;
224          else
225               return *(c + 1);
226     }
227     return (c == s) ? *c : *(c - 1);
228}
229
230# if 0
231static int strnof_delim(char *str, char odelim, char cdelim, int count[2])
232{
233  memset(count, 0, sizeof(*count)*2);
234  RL_EGG_BEGIN_TRACE;
235  RL_EGG_DEBUG("str: %s\n", str);
236  char *cp = strchr(str, '\0');
237  RL_EGG_END_TRACE;
238
239  if (cp == str)
240    return 1;
241
242  do {
243    if (cp != str && cpeek(cp, str, false) == '\\')
244      continue;
245
246    if (*cp == cdelim) {
247      ++count[1]; // increment close
248    } else if (*cp == odelim) {
249      ++count[0]; // increment open
250    }
251  } while(cp-- != str);
252
253  if (odelim == cdelim && count[1] > 0) {
254    if (count[1] % 2 == 1)
255      while(count[0]++ < --count[1]);
256    else {
257      count[0] = count[1] * 0.5;
258      count[1] *= 0.5;
259    }
260  }
261
262  RL_EGG_BEGIN_TRACE;
263  RL_EGG_DEBUG("open: %d\nclose: %d\n", count[0], count[1]);
264  RL_EGG_END_TRACE;
265  return 0;
266}
267# endif
268
269int *strndelim(const char *s, const char od, const char cd, int count[2])
270{
271     memset(count, 0, sizeof(*count)*2);
272     char *c = strchr(s, '\0');
273
274     if (c == s)
275          return NULL;
276
277     do {
278          if (c != s && cpeek(c, s, 0) == '\\')
279               continue;
280          if (*c == cd)
281               ++count[1];
282          else if (*c == od)
283               ++count[0];
284     } while (c-- != s);
285
286     if (od == cd && count[1] > 0) {
287          if (count[1] % 2 == 1)
288               while (count[0]++ < --count[1]);
289          else {
290               count[0] = count[1] * 0.5;
291               count[1] *= 0.5;
292          }
293     }
294
295     return count;
296}
297
298char *strwodqp(const char *src)
299{
300     size_t n = strlen(src) + 1;
301     int c[2] = {0, 0}, even = 0;
302     char *tmp, *token, *rest, *newp;
303     tmp = token = rest = newp = NULL;
304
305     if (!strndelim(src, '"', '"', c))
306          return NULL;
307
308     if (c[0] == 0)
309          return NULL;
310
311     tmp = strdup(src);
312     newp = malloc(n);
313     even = c[0] - abs(c[0] - c[1]);
314
315     token = strtok_r(tmp, "\"", &rest);
316
317     if (token == NULL) {
318          free(newp);
319          return NULL;
320     }
321
322     catl(newp, n, token);
323     while ((token = strtok_r(NULL, "\"", &rest)) != NULL) {
324          if (even % 2 == 1) {
325               catm(newp, n, newp, token);
326               --even;
327          } else {
328               ++even;
329          }
330     }
331
332     free(tmp);
333     return newp;
334}
Note: See TracBrowser for help on using the repository browser.