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); |