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