File Coverage

lib/Text/Wrap/Smart/XS.xs
Criterion Covered Total %
statement 78 81 96.3
branch 65 72 90.2
condition n/a
subroutine n/a
pod n/a
total 143 153 93.4


line stmt bran cond sub pod time code
1             #include "EXTERN.h"
2             #include "perl.h"
3             #include "XSUB.h"
4              
5             #include "ppport.h"
6              
7             #define PRE_PROCESS(text, string, t) do { \
8             char ch; \
9             subst_to_spaces (trim (text, &ch), &string); \
10             *(char *)(text + strlen (text)) = ch; \
11             spaces_to_space (string); \
12             t = string; \
13             } while (0)
14              
15             #define FINALIZE_STRING() do { \
16             *dest = '\0'; \
17             *string = buf; \
18             return; \
19             } while (0)
20              
21             #define IS_WHITESPACE(ws) \
22             (ws == ' ' || ws == '\f' || ws == '\n' || ws == '\r' || ws == '\t')
23              
24             #define SAVE_STRING(str, size, t) \
25             Newx (str, size + 1, char); \
26             \
27             strncpy (str, t, size); \
28             *(str + size) = '\0'; \
29             \
30             t += size; \
31             \
32             EXTEND (SP, 1); \
33             PUSHs (sv_2mortal(newSVpv(str, 0))); \
34             \
35             Safefree (str);
36              
37             static const char *
38 78           trim (const char *text, char *ch)
39             {
40             char *p;
41              
42 78           p = (char *)text + strlen (text);
43 94 100         while (p > text && IS_WHITESPACE (*(p - 1)))
    100          
    100          
    100          
    100          
44 16           p--;
45 78           *ch = *p;
46 78           *p = '\0';
47              
48             p = (char *)text;
49 92 100         while (IS_WHITESPACE (*p))
    100          
    100          
    100          
50 14           p++;
51 78           return p;
52             }
53              
54             static void
55 78           subst_to_spaces (const char *text, char **string)
56             {
57 78 100         if (strpbrk (text, "\f\n\r\t"))
58             {
59             const char *src = text;
60             char *dest;
61             char *buf, *ws;
62 6           const char *eot = text + strlen (text);
63 6           Newx (buf, strlen (text) + 1, char);
64             dest = buf;
65 18 100         while ((ws = strpbrk (src, "\f\n\r\t")))
66             {
67             char *p = ws;
68 12           strncpy (dest, src, ws - src);
69 12           dest += ws - src;
70             src += ws - src;
71 12           switch (*ws)
72             {
73 3           case '\f': p++; break; /* Form Feed */
74 3           case '\n': p++; break; /* LF */
75 3           case '\r': p++; break; /* CR */
76 3           case '\t': p++; break; /* Tab */
77 0           default: abort (); /* never reached */
78             }
79 12 100         if (*ws == '\r' && *p == '\n') /* CRLF */
    50          
80 0           p++;
81             src += p - ws;
82 12 50         if (p < eot)
83 12           *dest++ = ' ';
84             else
85 0           FINALIZE_STRING ();
86             }
87 6 50         if (src < eot)
88             {
89 6           strncpy (dest, src, eot - src);
90 6           dest += eot - src;
91             src += eot - src;
92             }
93 6           FINALIZE_STRING ();
94             }
95             else
96 72           *string = savepv (text);
97             }
98              
99             static void
100             spaces_to_space (char *string)
101             {
102             char *s, *p;
103             s = p = string;
104              
105 17860 100         while (*p)
    100          
106             {
107 17796 100         while (*p == ' ' && *(p + 1) == ' ')
    100          
    100          
    100          
108 14           p++;
109 17782           *s++ = *p++;
110             }
111 78           *s = '\0';
112             }
113              
114             static unsigned long
115 74           calc_average (unsigned long length, unsigned int wrap_at)
116             {
117             unsigned int i;
118 74           i = length / wrap_at;
119 74 100         if (length % wrap_at != 0)
120 34           i++;
121 74           return ceil ((double)length / (double)i);
122             }
123              
124             MODULE = Text::Wrap::Smart::XS PACKAGE = Text::Wrap::Smart::XS
125              
126             void
127             xs_exact_wrap (text, wrap_at)
128             const char *text;
129             unsigned int wrap_at;
130             PROTOTYPE: $$
131             INIT:
132             unsigned long average, length, offset;
133 10           char *string = NULL;
134             char *eot, *t;
135             PPCODE:
136 10           PRE_PROCESS (text, string, t);
137 10           length = strlen (t);
138 10           eot = t + length;
139              
140 10 100         if (length == 0)
141             {
142 2           Safefree (string);
143 2           XSRETURN_EMPTY;
144             }
145              
146 8           average = calc_average (length, wrap_at);
147              
148 26 100         for (offset = 0; offset < length && *t; offset += average)
    50          
149             {
150             char *str;
151 18           const unsigned long size = average > (eot - t) ? (eot - t) : average;
152              
153 18 50         SAVE_STRING (str, size, t);
154             }
155              
156 8           Safefree (string);
157              
158             void
159             xs_fuzzy_wrap (text, wrap_at)
160             const char *text;
161             unsigned int wrap_at;
162             PROTOTYPE: $$
163             INIT:
164             unsigned long average, length;
165 68           char *string = NULL;
166             char *t;
167             PPCODE:
168 68           PRE_PROCESS (text, string, t);
169 68           length = strlen (t);
170              
171 68 100         if (length == 0)
172             {
173 2           Safefree (string);
174 2           XSRETURN_EMPTY;
175             }
176              
177 66           average = calc_average (length, wrap_at);
178              
179 647 100         while (*t)
180             {
181             unsigned int spaces = 0;
182 581           long remaining = average;
183             unsigned long size;
184             char *str, *s;
185              
186             /* calculate pos and size of each chunk */
187 2621 100         for (s = t; *s;)
188             {
189 2555           char *ptr = strchr (s, ' ');
190 2555 100         if (ptr)
191             {
192             unsigned long next_space;
193             char *n, *p;
194             /* advance pos to space */
195 2489           remaining -= ptr - s;
196             p = s = ptr;
197             /* skip space */
198 2489           p++;
199             /* advance pos after space */
200 2489           remaining -= p - s;
201             /* get distance to next space */
202 2489           n = strchr (p, ' ');
203 2489 100         next_space = n ? n - p : 0;
204             /* pos and size complete */
205 2489 100         if (next_space > remaining && spaces >= 1)
206             break;
207 2300 100         else if (remaining <= 0)
208             break;
209 1974           spaces++;
210             s = p;
211             }
212             else
213 2040           s += strlen (s);
214             }
215 581           size = s - t;
216 581 50         if (!size)
217             break;
218              
219 581 50         SAVE_STRING (str, size, t);
220              
221 581 100         if (*t)
222 581           t++;
223             }
224              
225 66           Safefree (string);