File Coverage

LineBreak.xs
Criterion Covered Total %
statement 436 763 57.1
branch 360 1096 32.8
condition n/a
subroutine n/a
pod n/a
total 796 1859 42.8


line stmt bran cond sub pod time code
1             /*
2             * LineBreak.xs - Perl XS glue for Sombok package.
3             *
4             * Copyright (C) 2009-2013 Hatuka*nezumi - IKEDA Soji .
5             *
6             * This file is part of the Unicode::LineBreak package. This program is
7             * free software; you can redistribute it and/or modify it under the same
8             * terms as Perl itself.
9             *
10             * $Id$
11             */
12              
13             #include "EXTERN.h"
14             #include "perl.h"
15             #include "XSUB.h"
16             #define NEED_newRV_noinc
17             #define NEED_sv_2pv_flags
18             #define NEED_newRV_noinc_GLOBAL
19             #define NEED_sv_2pv_flags_GLOBAL
20             #define NEED_sv_2pv_nolen
21             #include "ppport.h"
22             #include "sombok.h"
23              
24             /* for Win32 with Visual Studio (MSVC) */
25             #ifdef _MSC_VER
26             # ifndef snprintf
27             # define snprintf _snprintf
28             # endif /* snprintf */
29             # define strcasecmp _stricmp
30             #endif /* _MSC_VER */
31              
32             /* Type synonyms for typemap. */
33             typedef IV swapspec_t;
34             typedef gcstring_t *generic_string;
35              
36             /***
37             *** Data conversion.
38             ***/
39              
40             /*
41             * Create Unicode string from Perl utf8-flagged string.
42             */
43             static
44 11236           unistr_t *SVtounistr(unistr_t *buf, SV *str)
45             {
46             U8 *utf8, *utf8ptr;
47             STRLEN utf8len, unilen, len;
48             unichar_t *uniptr;
49              
50 11236 50         if (buf == NULL) {
51 0 0         if ((buf = malloc(sizeof(unistr_t))) == NULL)
52 0           croak("SVtounistr: %s", strerror(errno));
53 11236 50         } else if (buf->str)
54 0           free(buf->str);
55 11236           buf->str = NULL;
56 11236           buf->len = 0;
57              
58 11236 50         if (SvOK(str))
    0          
    0          
59 11236 50         utf8 = (U8 *)SvPV(str, utf8len);
60             else
61 0           return buf;
62 11236 50         if (utf8len <= 0)
63 0           return buf;
64 11236           unilen = utf8_length(utf8, utf8 + utf8len);
65 11236 50         if ((buf->str = (unichar_t *)malloc(sizeof(unichar_t) * unilen)) == NULL)
66 0           croak("SVtounistr: %s", strerror(errno));
67              
68 11236           utf8ptr = utf8;
69 11236           uniptr = buf->str;
70 98265 100         while (utf8ptr < utf8 + utf8len) {
71             #if PERL_VERSION >= 20 || (PERL_VERSION == 19 && PERL_SUBVERSION >= 4)
72 87029 50         *uniptr = (unichar_t) NATIVE_TO_UNI(
73             utf8_to_uvchr_buf(utf8ptr, utf8 + utf8len, &len));
74             #elif PERL_VERSION >= 16 || (PERL_VERSION == 15 && PERL_SUBVERSION >= 9)
75             *uniptr = (unichar_t) utf8_to_uvuni_buf(utf8ptr, utf8 + utf8len,
76             &len);
77             #else
78             *uniptr = (unichar_t) utf8n_to_uvuni(utf8ptr,
79             utf8 + utf8len - utf8ptr, &len,
80             ckWARN(WARN_UTF8) ? 0 :
81             UTF8_ALLOW_ANY);
82             #endif
83             if (len < 0) {
84             free(buf->str);
85             buf->str = NULL;
86             buf->len = 0;
87             croak("SVtounistr: Not well-formed UTF-8");
88             }
89 87029 50         if (len == 0) {
90 0           free(buf->str);
91 0           buf->str = NULL;
92 0           buf->len = 0;
93 0           croak("SVtounistr: Internal error");
94             }
95 87029           utf8ptr += len;
96 87029           uniptr++;
97             }
98 11236           buf->len = unilen;
99 11236           return buf;
100             }
101              
102             /*
103             * Create Unicode string from Perl string NOT utf8-flagged.
104             */
105             static
106 35           unistr_t *SVupgradetounistr(unistr_t *buf, SV *str)
107             {
108             char *s;
109             size_t len, i;
110              
111 35 50         if (buf == NULL) {
112 0 0         if ((buf = malloc(sizeof(unistr_t))) == NULL)
113 0           croak("SVupgradetounistr: %s", strerror(errno));
114 35 50         } else if (buf->str)
115 0           free(buf->str);
116 35           buf->str = NULL;
117 35           buf->len = 0;
118              
119 35 50         if (SvOK(str))
    0          
    0          
120 35 100         s = SvPV(str, len);
121             else
122 0           return buf;
123 35 50         if (len == 0)
124 0           return buf;
125 35 50         if ((buf->str = malloc(sizeof(unichar_t) * len)) == NULL)
126 0           croak("SVupgradetounistr: %s", strerror(errno));
127              
128 97 100         for (i = 0; i < len; i++)
129 62           buf->str[i] = (unichar_t)(unsigned char)s[i];
130 35           buf->len = len;
131 35           return buf;
132             }
133              
134             /*
135             * Create Perl utf8-flagged string from Unicode string.
136             */
137             static
138 14560           SV *unistrtoSV(unistr_t *unistr, size_t uniidx, size_t unilen)
139             {
140 14560           U8 *buf = NULL, *newbuf;
141             STRLEN utf8len;
142             unichar_t *uniptr;
143             SV *utf8;
144              
145 14560 50         if (unistr == NULL || unistr->str == NULL || unilen == 0) {
    100          
    100          
146 2230           utf8 = newSVpvn("", 0);
147 2230           SvUTF8_on(utf8);
148 2230           return utf8;
149             }
150              
151 12330           utf8len = 0;
152 12330           uniptr = unistr->str + uniidx;
153 114711 100         while (uniptr < unistr->str + uniidx + unilen &&
    50          
154 102381           uniptr < unistr->str + unistr->len) {
155 102381 50         if ((newbuf = realloc(buf,
156 102381           sizeof(U8) * (utf8len + UTF8_MAXLEN + 1)))
157             == NULL) {
158 0           free(buf);
159 0           croak("unistrtoSV: %s", strerror(errno));
160             }
161 102381           buf = newbuf;
162             #if PERL_VERSION >= 20 || (PERL_VERSION == 19 && PERL_SUBVERSION >= 4)
163 102381           utf8len = uvchr_to_utf8(buf + utf8len, UNI_TO_NATIVE(*uniptr)) - buf;
164             #else
165             utf8len = uvuni_to_utf8(buf + utf8len, *uniptr) - buf;
166             #endif
167 102381           uniptr++;
168             }
169              
170 12330           utf8 = newSVpvn((char *)(void *)buf, utf8len);
171 12330           SvUTF8_on(utf8);
172 12330           free(buf);
173 12330           return utf8;
174             }
175              
176             /*
177             * Convert Perl object to C object
178             */
179             #define PerltoC(type, arg) \
180             (INT2PTR(type, SvIV((SV *)SvRV(arg))))
181              
182             /*
183             * Create Perl object from C object
184             */
185             # define setCtoPerl(arg, klass, var) \
186             STMT_START { \
187             sv_setref_iv(arg, klass, (IV)(var)); \
188             SvREADONLY_on(arg); \
189             } STMT_END
190             static
191 32684           SV *CtoPerl(char *klass, void *obj)
192             {
193             SV *sv;
194              
195 32684           sv = newSViv(0);
196 32684           setCtoPerl(sv, klass, obj);
197 32684           return sv;
198             }
199              
200             /*
201             * Convert Perl utf8-flagged string (GCString) to grapheme cluster string.
202             */
203             static
204 575           gcstring_t *SVtogcstring(SV *sv, linebreak_t *lbobj)
205             {
206 575           unistr_t unistr = {NULL, 0};
207              
208 575 100         if (!sv_isobject(sv)) {
209 465           SVtounistr(&unistr, sv);
210 465           return gcstring_new(&unistr, lbobj);
211 110 50         } else if (sv_derived_from(sv, "Unicode::GCString"))
212 110 50         return PerltoC(gcstring_t *, sv);
213             else
214 575 0         croak("Unknown object %s", HvNAME(SvSTASH(SvRV(sv))));
    0          
    0          
    0          
    0          
    0          
215             }
216              
217             #if 0
218             /*
219             * Convert Perl LineBreak object to C linebreak object.
220             */
221             static
222             linebreak_t *SVtolinebreak(SV *sv)
223             {
224             if (!sv_isobject(sv))
225             croak("Not object");
226             else if (sv_derived_from(sv, "Unicode::LineBreak"))
227             return PerltoC(linebreak_t *, sv);
228             else
229             croak("Unknown object %s", HvNAME(SvSTASH(SvRV(sv))));
230             }
231             #endif /* 0 */
232              
233             /*
234             * Convert Perl SV to boolean (n.b. string "YES" means true).
235             */
236             static
237 2737           int SVtoboolean(SV *sv)
238             {
239             char *str;
240              
241 2737 50         if (!sv || !SvOK(sv))
    50          
    0          
    0          
242 0           return 0;
243 2737 50         if (SvPOK(sv))
244 3571 50         return strcasecmp((str = SvPV_nolen(sv)), "YES") == 0 ||
245 834           atof(str) != 0.0;
246 0 0         return SvNV(sv) != 0.0;
247             }
248              
249             /***
250             *** Other utilities
251             ***/
252              
253             /*
254             * Do regex match once then returns offset and length.
255             */
256 81           void do_pregexec_once(REGEXP *rx, unistr_t *str)
257             {
258             SV *screamer;
259             char *str_arg, *str_beg, *str_end;
260             size_t offs_beg, offs_end;
261              
262 81           screamer = unistrtoSV(str, 0, str->len);
263 81           SvREADONLY_on(screamer);
264 81           str_beg = str_arg = SvPVX(screamer);
265 81           str_end = SvEND(screamer);
266              
267 81 100         if (pregexec(rx, str_arg, str_end, str_beg, 0, screamer, 1)) {
268             #if PERL_VERSION >= 11
269 49           offs_beg = ((regexp *)SvANY(rx))->offs[0].start;
270 49           offs_end = ((regexp *)SvANY(rx))->offs[0].end;
271             #elif ((PERL_VERSION == 10) || (PERL_VERSION == 9 && PERL_SUBVERSION >= 5))
272             offs_beg = rx->offs[0].start;
273             offs_end = rx->offs[0].end;
274             #else /* PERL_VERSION */
275             offs_beg = rx->startp[0];
276             offs_end = rx->endp[0];
277             #endif
278 49           str->str += utf8_length((U8 *)str_beg, (U8 *)(str_beg + offs_beg));
279 49           str->len = utf8_length((U8 *)(str_beg + offs_beg),
280             (U8 *)(str_beg + offs_end));
281             } else
282 32           str->str = NULL;
283              
284 81           SvREFCNT_dec(screamer);
285 81           }
286              
287             /***
288             *** Callbacks for Sombok library.
289             ***/
290              
291             /*
292             * Increment/decrement reference count
293             */
294 1040           void ref_func(void *sv, int datatype, int d)
295             {
296 1040 50         if (sv == NULL)
297 0           return;
298 1040 100         if (0 < d)
299 520           SvREFCNT_inc((SV *)sv);
300 520 50         else if (d < 0)
301 520           SvREFCNT_dec((SV *)sv);
302             }
303              
304             /*
305             * Call preprocessing function
306             */
307             static
308 130           gcstring_t *prep_func(linebreak_t *lbobj, void *dataref, unistr_t *str,
309             unistr_t *text)
310             {
311             AV *data;
312 130           SV *sv, **pp, *func = NULL;
313 130           REGEXP *rx = NULL;
314             size_t count, i, j;
315             gcstring_t *gcstr, *ret;
316              
317 130 50         if (dataref == NULL ||
    50          
318 130           (data = (AV *)SvRV((SV *)dataref)) == NULL)
319 0           return (lbobj->errnum = EINVAL), NULL;
320              
321             /* Pass I */
322              
323 130 100         if (text != NULL) {
324 81 50         if ((pp = av_fetch(data, 0, 0)) == NULL)
325 0           return (lbobj->errnum = EINVAL), NULL;
326              
327             #if ((PERL_VERSION >= 10) || (PERL_VERSION >= 9 && PERL_SUBVERSION >= 5))
328 81 50         if (SvRXOK(*pp))
329 81           rx = SvRX(*pp);
330             #else /* PERL_VERSION */
331             if (SvROK(*pp) && SvMAGICAL(sv = SvRV(*pp))) {
332             MAGIC *mg;
333             if ((mg = mg_find(sv, PERL_MAGIC_qr)) != NULL)
334             rx = (REGEXP *)mg->mg_obj;
335             }
336             #endif /* PERL_VERSION */
337 81 50         if (rx == NULL)
338 0           return (lbobj->errnum = EINVAL), NULL;
339              
340 81           do_pregexec_once(rx, str);
341 81           return NULL;
342             }
343              
344             /* Pass II */
345              
346 49 50         if ((pp = av_fetch(data, 1, 0)) == NULL)
347 0           func = NULL;
348 49 50         else if (SvOK(*pp))
    0          
    0          
349 49           func = *pp;
350             else
351 0           func = NULL;
352              
353 49 50         if (func == NULL) {
354 0 0         if ((ret = gcstring_newcopy(str, lbobj)) == NULL)
355 0 0         return (lbobj->errnum = errno ? errno : ENOMEM), NULL;
356             } else {
357 49           dSP;
358 49           ENTER;
359 49           SAVETMPS;
360 49 50         PUSHMARK(SP);
361 49           linebreak_incref(lbobj); /* mortal but should not be destroyed.*/
362 49 50         XPUSHs(sv_2mortal(CtoPerl("Unicode::LineBreak", lbobj)));
363 49 50         XPUSHs(sv_2mortal(unistrtoSV(str, 0, str->len)));
364 49           PUTBACK;
365 49           count = call_sv(func, G_ARRAY | G_EVAL);
366              
367 49           SPAGAIN;
368 49 50         if (SvTRUE(ERRSV)) {
    50          
    50          
    50          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
369 0 0         if (!lbobj->errnum)
370 0           lbobj->errnum = LINEBREAK_EEXTN;
371 0           return NULL;
372             }
373              
374 49 50         if ((ret = gcstring_new(NULL, lbobj)) == NULL)
375 0 0         return (lbobj->errnum = errno ? errno : ENOMEM), NULL;
376              
377 270 100         for (i = 0; i < count; i++) {
378 221           sv = POPs;
379 221 50         if (!SvOK(sv))
    0          
    0          
380 0           continue;
381 221           gcstr = SVtogcstring(sv, lbobj);
382              
383 2550 100         for (j = 0; j < gcstr->gclen; j++) {
384 2329 50         if (gcstr->gcstr[j].flag &
385             (LINEBREAK_FLAG_ALLOW_BEFORE |
386             LINEBREAK_FLAG_PROHIBIT_BEFORE))
387 0           continue;
388 2329 100         if (i < count - 1 && j == 0)
    100          
389 172           gcstr->gcstr[j].flag |= LINEBREAK_FLAG_ALLOW_BEFORE;
390 2157 100         else if (0 < j)
391 2108           gcstr->gcstr[j].flag |= LINEBREAK_FLAG_PROHIBIT_BEFORE;
392             }
393              
394 221           gcstring_replace(ret, 0, 0, gcstr);
395 221 50         if (!sv_isobject(sv))
396 221           gcstring_destroy(gcstr);
397             }
398              
399 49           PUTBACK;
400 49 50         FREETMPS;
401 49           LEAVE;
402             }
403              
404 49           return ret;
405             }
406              
407             /*
408             * Call format function
409             */
410             static
411             char *linebreak_states[] = {
412             NULL, "sot", "sop", "sol", "", "eol", "eop", "eot", NULL
413             };
414             static
415 756           gcstring_t *format_func(linebreak_t *lbobj, linebreak_state_t action,
416             gcstring_t *str)
417             {
418             SV *sv;
419             char *actionstr;
420             int count;
421             gcstring_t *ret;
422              
423 756           dSP;
424 756 50         if (action <= LINEBREAK_STATE_NONE || LINEBREAK_STATE_MAX <= action)
    50          
425 0           return NULL;
426 756           actionstr = linebreak_states[(size_t)action];
427 756           ENTER;
428 756           SAVETMPS;
429 756 50         PUSHMARK(SP);
430 756           linebreak_incref(lbobj); /* mortal but should not be destroyed. */
431 756 50         XPUSHs(sv_2mortal(CtoPerl("Unicode::LineBreak", lbobj)));
432 756 50         XPUSHs(sv_2mortal(newSVpv(actionstr, 0)));
433 756 50         XPUSHs(sv_2mortal(CtoPerl("Unicode::GCString", gcstring_copy(str))));
434 756           PUTBACK;
435 756           count = call_sv(lbobj->format_data, G_SCALAR | G_EVAL);
436              
437 756           SPAGAIN;
438 756 50         if (SvTRUE(ERRSV)) {
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
439 0 0         if (!lbobj->errnum)
440 0           lbobj->errnum = LINEBREAK_EEXTN;
441 0           POPs;
442 0           return NULL;
443 756 50         } else if (count != 1)
444 0           croak("format_func: internal error");
445             else
446 756           sv = POPs;
447 756 100         if (!SvOK(sv))
    50          
    50          
448 402           ret = NULL;
449             else
450 354           ret = SVtogcstring(sv, lbobj);
451 756 100         if (sv_isobject(sv))
452 110           ret = gcstring_copy(ret);
453              
454 756           PUTBACK;
455 756 50         FREETMPS;
456 756           LEAVE;
457              
458 756           return ret;
459             }
460              
461             /*
462             * Call sizing function
463             */
464             static
465 2328           double sizing_func(linebreak_t *lbobj, double len,
466             gcstring_t *pre, gcstring_t *spc, gcstring_t *str)
467             {
468             int count;
469             double ret;
470              
471 2328           dSP;
472 2328           ENTER;
473 2328           SAVETMPS;
474 2328 50         PUSHMARK(SP);
475 2328           linebreak_incref(lbobj); /* mortal but should not be destroyed. */
476 2328 50         XPUSHs(sv_2mortal(CtoPerl("Unicode::LineBreak", lbobj)));
477 2328 50         XPUSHs(sv_2mortal(newSVnv(len)));
478 2328 50         XPUSHs(sv_2mortal(CtoPerl("Unicode::GCString", gcstring_copy(pre))));
479 2328 50         XPUSHs(sv_2mortal(CtoPerl("Unicode::GCString", gcstring_copy(spc))));
480 2328 50         XPUSHs(sv_2mortal(CtoPerl("Unicode::GCString", gcstring_copy(str))));
481 2328           PUTBACK;
482 2328           count = call_sv(lbobj->sizing_data, G_SCALAR | G_EVAL);
483              
484 2328           SPAGAIN;
485 2328 50         if (SvTRUE(ERRSV)) {
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
486 0 0         if (!lbobj->errnum)
487 0           lbobj->errnum = LINEBREAK_EEXTN;
488 0           POPs;
489 0           return -1;
490 2328 50         } else if (count != 1)
491 0           croak("sizing_func: internal error");
492             else
493 2328 50         ret = POPn;
494              
495 2328           PUTBACK;
496 2328 50         FREETMPS;
497 2328           LEAVE;
498              
499 2328           return ret;
500             }
501              
502             /*
503             * Call urgent breaking function
504             */
505             static
506 0           gcstring_t *urgent_func(linebreak_t *lbobj, gcstring_t *str)
507             {
508             SV *sv;
509             int count;
510             size_t i;
511             gcstring_t *gcstr, *ret;
512              
513 0           dSP;
514 0           ENTER;
515 0           SAVETMPS;
516 0 0         PUSHMARK(SP);
517 0           linebreak_incref(lbobj); /* mortal but should not be destroyed. */
518 0 0         XPUSHs(sv_2mortal(CtoPerl("Unicode::LineBreak", lbobj)));
519 0 0         XPUSHs(sv_2mortal(CtoPerl("Unicode::GCString", gcstring_copy(str))));
520 0           PUTBACK;
521 0           count = call_sv(lbobj->urgent_data, G_ARRAY | G_EVAL);
522              
523 0           SPAGAIN;
524 0 0         if (SvTRUE(ERRSV)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
525 0 0         if (!lbobj->errnum)
526 0           lbobj->errnum = LINEBREAK_EEXTN;
527 0           return NULL;
528 0 0         } if (count == 0)
529 0           return NULL;
530              
531 0           ret = gcstring_new(NULL, lbobj);
532 0 0         for (i = count; i; i--) {
533 0           sv = POPs;
534 0 0         if (SvOK(sv)) {
    0          
    0          
535 0           gcstr = SVtogcstring(sv, lbobj);
536 0 0         if (gcstr->gclen)
537 0           gcstr->gcstr[0].flag = LINEBREAK_FLAG_ALLOW_BEFORE;
538 0           gcstring_replace(ret, 0, 0, gcstr);
539 0 0         if (!sv_isobject(sv))
540 0           gcstring_destroy(gcstr);
541             }
542             }
543              
544 0           PUTBACK;
545 0 0         FREETMPS;
546 0           LEAVE;
547              
548 0           return ret;
549             }
550              
551              
552             MODULE = Unicode::LineBreak PACKAGE = Unicode::LineBreak
553              
554             void
555             EAWidths()
556             INIT:
557             char **p;
558             PPCODE:
559 210 100         for (p = (char **)linebreak_propvals_EA; *p != NULL; p++)
560 189 50         XPUSHs(sv_2mortal(newSVpv(*p, 0)));
561              
562             void
563             LBClasses()
564             INIT:
565             char **p;
566             PPCODE:
567 861 100         for (p = (char **)linebreak_propvals_LB; *p != NULL; p++)
568 840 50         XPUSHs(sv_2mortal(newSVpv(*p, 0)));
569              
570             linebreak_t *
571             _new(klass)
572             char *klass;
573             PROTOTYPE: $
574             CODE:
575 483 50         if ((RETVAL = linebreak_new(ref_func)) == NULL)
576 0           croak("%s->_new: %s", klass, strerror(errno));
577 483           linebreak_set_stash(RETVAL, newRV_noinc((SV *)newHV()));
578 483           SvREFCNT_dec(RETVAL->stash); /* fixup */
579             OUTPUT:
580             RETVAL
581              
582             linebreak_t *
583             copy(self)
584             linebreak_t *self;
585             PROTOTYPE: $
586             CODE:
587 0           RETVAL = linebreak_copy(self);
588             OUTPUT:
589             RETVAL
590              
591             void
592             DESTROY(self)
593             linebreak_t *self;
594             PROTOTYPE: $
595             CODE:
596 3616           linebreak_destroy(self);
597              
598             SV *
599             _config(self, ...)
600             linebreak_t *self;
601             PREINIT:
602             size_t i;
603             char *key;
604             void *func;
605             SV *val;
606             char *opt;
607             CODE:
608 1351           RETVAL = NULL;
609 1351 50         if (items < 2)
610 0           croak("_config: Too few arguments");
611 1351 100         else if (items < 3) {
612 353 50         key = (char *)SvPV_nolen(ST(1));
613              
614 353 50         if (strcasecmp(key, "BreakIndent") == 0)
615 0           RETVAL = newSVuv(self->options &
616             LINEBREAK_OPTION_BREAK_INDENT);
617 353 50         else if (strcasecmp(key, "CharMax") == 0)
618 0           RETVAL = newSVuv(self->charmax);
619 353 100         else if (strcasecmp(key, "ColMax") == 0)
620 56           RETVAL = newSVnv((NV)self->colmax);
621 297 50         else if (strcasecmp(key, "ColMin") == 0)
622 0           RETVAL = newSVnv((NV)self->colmin);
623 297 50         else if (strcasecmp(key, "ComplexBreaking") == 0)
624 0           RETVAL = newSVuv(self->options &
625             LINEBREAK_OPTION_COMPLEX_BREAKING);
626 297 50         else if (strcasecmp(key, "Context") == 0) {
627 0 0         if (self->options & LINEBREAK_OPTION_EASTASIAN_CONTEXT)
628 0           RETVAL = newSVpvn("EASTASIAN", 9);
629             else
630 0           RETVAL = newSVpvn("NONEASTASIAN", 12);
631 297 50         } else if (strcasecmp(key, "EAWidth") == 0) {
632 0           AV *av, *codes = NULL, *ret = NULL;
633 0           propval_t p = PROP_UNKNOWN;
634             unichar_t c;
635             size_t i;
636              
637 0 0         if (self->map == NULL || self->mapsiz == 0)
    0          
638 0           XSRETURN_UNDEF;
639              
640 0 0         for (i = 0; i < self->mapsiz; i++)
641 0 0         if (self->map[i].eaw != PROP_UNKNOWN) {
642 0 0         if (p != self->map[i].eaw){
643 0           p = self->map[i].eaw;
644 0           codes = newAV();
645 0           av = newAV();
646 0           av_push(av, newRV_noinc((SV *)codes));
647 0           av_push(av, newSViv((IV)p));
648 0 0         if (ret == NULL)
649 0           ret = newAV();
650 0           av_push(ret, newRV_noinc((SV *)av));
651             }
652 0 0         for (c = self->map[i].beg; c <= self->map[i].end; c++)
653 0           av_push(codes, newSVuv(c));
654             }
655              
656 0 0         if (ret == NULL)
657 0           XSRETURN_UNDEF;
658 0           RETVAL = newRV_noinc((SV *)ret);
659 297 50         } else if (strcasecmp(key, "Format") == 0) {
660 0           func = self->format_func;
661 0 0         if (func == NULL)
662 0           XSRETURN_UNDEF;
663 0 0         else if (func == linebreak_format_NEWLINE)
664 0           RETVAL = newSVpvn("NEWLINE", 7);
665 0 0         else if (func == linebreak_format_SIMPLE)
666 0           RETVAL = newSVpvn("SIMPLE", 6);
667 0 0         else if (func == linebreak_format_TRIM)
668 0           RETVAL = newSVpvn("TRIM", 4);
669 0 0         else if (func == format_func) {
670 0 0         if ((val = (SV *)self->format_data) == NULL)
671 0           XSRETURN_UNDEF;
672 0           ST(0) = val; /* should not be mortal. */
673 0           XSRETURN(1);
674             } else
675 0           croak("_config: internal error");
676 297 50         } else if (strcasecmp(key, "HangulAsAL") == 0)
677 0           RETVAL = newSVuv(self->options &
678             LINEBREAK_OPTION_HANGUL_AS_AL);
679 297 50         else if (strcasecmp(key, "LBClass") == 0) {
680 0           AV *av, *codes = NULL, *ret = NULL;
681 0           propval_t p = PROP_UNKNOWN;
682             unichar_t c;
683             size_t i;
684              
685 0 0         if (self->map == NULL || self->mapsiz == 0)
    0          
686 0           XSRETURN_UNDEF;
687              
688 0 0         for (i = 0; i < self->mapsiz; i++)
689 0 0         if (self->map[i].lbc != PROP_UNKNOWN) {
690 0 0         if (p != self->map[i].lbc){
691 0           p = self->map[i].lbc;
692 0           codes = newAV();
693 0           av = newAV();
694 0           av_push(av, newRV_noinc((SV *)codes));
695 0           av_push(av, newSViv((IV)p));
696 0 0         if (ret == NULL)
697 0           ret = newAV();
698 0           av_push(ret, newRV_noinc((SV *)av));
699             }
700 0 0         for (c = self->map[i].beg; c <= self->map[i].end; c++)
701 0           av_push(codes, newSVuv(c));
702             }
703              
704 0 0         if (ret == NULL)
705 0           XSRETURN_UNDEF;
706 0           RETVAL = newRV_noinc((SV *)ret);
707 297 50         } else if (strcasecmp(key, "LegacyCM") == 0)
708 0           RETVAL = newSVuv(self->options & LINEBREAK_OPTION_LEGACY_CM);
709 297 50         else if (strcasecmp(key, "Newline") == 0) {
710 297           unistr_t unistr = {self->newline.str, self->newline.len};
711 297 50         if (self->newline.str == NULL || self->newline.len == 0)
    50          
712 0           RETVAL = unistrtoSV(&unistr, 0, 0);
713             else
714 297           RETVAL = unistrtoSV(&unistr, 0, self->newline.len);
715 0 0         } else if (strcasecmp(key, "Prep") == 0) {
716             AV *av;
717 0 0         if (self->prep_func == NULL || self->prep_func[0] == NULL)
    0          
718 0           XSRETURN_UNDEF;
719 0           av = newAV();
720 0 0         for (i = 0; (func = self->prep_func[i]) != NULL; i++)
721 0 0         if (func == linebreak_prep_URIBREAK) {
722 0 0         if (self->prep_data == NULL ||
    0          
723 0           self->prep_data[i] == NULL)
724 0           av_push(av, newSVpvn("NONBREAKURI", 11));
725             else
726 0           av_push(av, newSVpvn("BREAKURI", 8));
727 0 0         } else if (func == prep_func) {
728 0 0         if (self->prep_data == NULL ||
    0          
729 0           self->prep_data[i] == NULL)
730 0           croak("_config: internal error");
731 0           SvREFCNT_inc(self->prep_data[i]); /* avoid freed */
732 0           av_push(av, self->prep_data[i]);
733             } else
734 0           croak("_config: internal error");
735 0           RETVAL = newRV_noinc((SV *)av);
736 0 0         } else if (strcasecmp(key, "Sizing") == 0) {
737 0           func = self->sizing_func;
738 0 0         if (func == NULL)
739 0           XSRETURN_UNDEF;
740 0 0         else if (func == linebreak_sizing_UAX11)
741 0           RETVAL = newSVpvn("UAX11", 5);
742 0 0         else if (func == sizing_func) {
743 0 0         if ((val = (SV *)self->sizing_data) == NULL)
744 0           XSRETURN_UNDEF;
745 0           ST(0) = val; /* should not be mortal. */
746 0           XSRETURN(1);
747             } else
748 0           croak("_config: internal error");
749 0 0         } else if (strcasecmp(key, "Urgent") == 0) {
750 0           func = self->urgent_func;
751 0 0         if (func == NULL)
752 0           XSRETURN_UNDEF;
753 0 0         else if (func == linebreak_urgent_ABORT)
754 0           RETVAL = newSVpvn("CROAK", 5);
755 0 0         else if (func == linebreak_urgent_FORCE)
756 0           RETVAL = newSVpvn("FORCE", 5);
757 0 0         else if (func == urgent_func) {
758 0 0         if ((val = (SV *)self->urgent_data) == NULL)
759 0           XSRETURN_UNDEF;
760 0           ST(0) = val; /* should not be mortal. */
761 0           XSRETURN(1);
762             } else
763 0           croak("_config: internal error");
764 0 0         } else if (strcasecmp(key, "ViramaAsJoiner") == 0)
765 0           RETVAL = newSVuv(self->options & LINEBREAK_OPTION_VIRAMA_AS_JOINER);
766             else {
767 0           warn("_config: Getting unknown option %s", key);
768 0           XSRETURN_UNDEF;
769             }
770 998 50         } else if (!(items % 2))
771 0           croak("_config: Argument size mismatch");
772 9235 100         else for (RETVAL = NULL, i = 1; i < items; i += 2) {
773 8237 50         if (!SvPOK(ST(i)))
774 0           croak("_config: Illegal argument");
775 8237 50         key = (char *)SvPV_nolen(ST(i));
776 8237           val = ST(i + 1);
777              
778 8237 100         if (strcasecmp(key, "Prep") == 0) {
779             SV *sv, *pattern, *func;
780             AV *av;
781 497           REGEXP *rx = NULL;
782              
783 497 100         if (! SvOK(val))
    50          
    50          
784 483           linebreak_add_prep(self, NULL, NULL);
785 14 100         else if (SvROK(val) &&
    50          
786 11 50         SvTYPE(av = (AV *)SvRV(val)) == SVt_PVAV &&
787 11           0 < av_len(av) + 1) {
788 11           pattern = *av_fetch(av, 0, 0);
789             #if ((PERL_VERSION >= 10) || (PERL_VERSION >= 9 && PERL_SUBVERSION >= 5))
790 11 100         if (SvRXOK(pattern))
791 10           rx = SvRX(pattern);
792             #else /* PERL_VERSION */
793             if (SvROK(pattern) && SvMAGICAL(sv = SvRV(pattern))) {
794             MAGIC *mg;
795             if ((mg = mg_find(sv, PERL_MAGIC_qr)) != NULL)
796             rx = (REGEXP *)mg->mg_obj;
797             }
798             #endif
799 11 100         if (rx != NULL)
800 10           SvREFCNT_inc(pattern); /* FIXME:avoid freed */
801 1 50         else if (SvOK(pattern)) {
    0          
    0          
802             #if ((PERL_VERSION >= 10) || (PERL_VERSION == 9 && PERL_SUBVERSION >= 5))
803 1           rx = pregcomp(pattern, 0);
804             #else /* PERL_VERSION */
805             {
806             PMOP *pm;
807             New(1, pm, 1, PMOP);
808             rx = pregcomp(SvPVX(pattern), SvEND(pattern), pm);
809             }
810             #endif
811 2 50         if (rx != NULL) {
812             #if PERL_VERSION >= 11
813 1           pattern = newRV_noinc((SV *)rx);
814 1           sv_bless(pattern, gv_stashpv("Regexp", 0));
815             #else /* PERL_VERSION */
816             sv = newSV(0);
817             sv_magic(sv, (SV *)rx, PERL_MAGIC_qr, NULL, 0);
818             pattern = newRV_noinc(sv);
819             sv_bless(pattern, gv_stashpv("Regexp", 0));
820             #endif
821             }
822             } else
823 0           rx = NULL;
824              
825 11 50         if (rx == NULL)
826 0           croak("_config: Not a regex");
827              
828 11 50         if (av_fetch(av, 1, 0) == NULL)
829 0           func = NULL;
830 11 50         else if (SvOK(func = *av_fetch(av, 1, 0)))
    0          
    0          
831 11           SvREFCNT_inc(func); /* avoid freed */
832             else
833 0           func = NULL;
834              
835 11           av = newAV();
836 11           av_push(av, pattern);
837 11 50         if (func != NULL)
838 11           av_push(av, func);
839 11           sv = newRV_noinc((SV *)av);
840 11           linebreak_add_prep(self, prep_func, (void *)sv);
841 11           SvREFCNT_dec(sv); /* fixup */
842             } else {
843 3 50         char *s = SvPV_nolen(val);
844              
845 3 100         if (strcasecmp(s, "BREAKURI") == 0)
846 1           linebreak_add_prep(self, linebreak_prep_URIBREAK, val);
847 2 50         else if (strcasecmp(s, "NONBREAKURI") == 0)
848 2           linebreak_add_prep(self, linebreak_prep_URIBREAK,
849             NULL);
850             else
851 497           croak("_config: Unknown preprocess option: %s", s);
852             }
853 7740 100         } else if (strcasecmp(key, "Format") == 0) {
854 509 100         if (! SvOK(val))
    50          
    50          
855 1           linebreak_set_format(self, NULL, NULL);
856 508 100         else if (sv_derived_from(val, "CODE"))
857 17           linebreak_set_format(self, format_func, (void *)val);
858             else {
859 491 50         char *s = SvPV_nolen(val);
860              
861 491 50         if (strcasecmp(s, "DEFAULT") == 0) {
862 0           warn("_config: "
863             "Method name \"DEFAULT\" for Format option was "
864             "obsoleted. Use \"SIMPLE\"");
865 0           linebreak_set_format(self, linebreak_format_SIMPLE,
866             NULL);
867 491 100         } else if (strcasecmp(s, "SIMPLE") == 0)
868 483           linebreak_set_format(self, linebreak_format_SIMPLE,
869             NULL);
870 8 100         else if (strcasecmp(s, "NEWLINE") == 0)
871 4           linebreak_set_format(self, linebreak_format_NEWLINE,
872             NULL);
873 4 50         else if (strcasecmp(s, "TRIM") == 0)
874 4           linebreak_set_format(self, linebreak_format_TRIM,
875             NULL);
876             else
877 509           croak("_config: Unknown Format option: %s", s);
878             }
879 7231 100         } else if (strcasecmp(key, "Sizing") == 0) {
880 491 50         if (! SvOK(val))
    0          
    0          
881 0           linebreak_set_sizing(self, NULL, NULL);
882 491 100         else if (sv_derived_from(val, "CODE"))
883 8           linebreak_set_sizing(self, sizing_func, (void *)val);
884             else {
885 483 50         char *s = SvPV_nolen(val);
886              
887 483 50         if (strcasecmp(s, "DEFAULT") == 0) {
888 0           warn("_config: "
889             "Method name \"DEFAULT\" for Sizing option "
890             "was obsoleted. Use \"UAX11\"");
891 0           linebreak_set_sizing(self, linebreak_sizing_UAX11,
892             NULL);
893 483 50         } else if (strcasecmp(s, "UAX11") == 0)
894 483           linebreak_set_sizing(self, linebreak_sizing_UAX11,
895             NULL);
896             else
897 491           croak("_config: Unknown Sizing option: %s", s);
898             }
899 6740 100         } else if (strcasecmp(key, "Urgent") == 0) {
900 489 100         if (! SvOK(val))
    50          
    50          
901 483           linebreak_set_urgent(self, NULL, NULL);
902 6 50         else if (sv_derived_from(val, "CODE"))
903 0           linebreak_set_urgent(self, urgent_func, (void *)val);
904             else {
905 6 50         char *s = SvPV_nolen(val);
906              
907 6 50         if (strcasecmp(s, "NONBREAK") == 0) {
908 0           warn("_config: "
909             "Method name \"NONBREAK\" for Urgent "
910             "option was obsoleted. Use undef");
911 0           linebreak_set_urgent(self, NULL, NULL);
912 6 100         } else if (strcasecmp(s, "CROAK") == 0)
913 2           linebreak_set_urgent(self, linebreak_urgent_ABORT,
914             NULL);
915 4 50         else if (strcasecmp(s, "FORCE") == 0)
916 4           linebreak_set_urgent(self, linebreak_urgent_FORCE,
917             NULL);
918             else
919 489           croak("_config: Unknown Urgent option: %s", s);
920             }
921 6251 100         } else if (strcasecmp(key, "BreakIndent") == 0) {
922 358 100         if (SVtoboolean(val))
923 357           self->options |= LINEBREAK_OPTION_BREAK_INDENT;
924             else
925 358           self->options &= ~LINEBREAK_OPTION_BREAK_INDENT;
926 5893 100         } else if (strcasecmp(key, "CharMax") == 0)
927 485 50         self->charmax = SvUV(val);
928 5408 100         else if (strcasecmp(key, "ColMax") == 0)
929 538 100         self->colmax = (double)SvNV(val);
930 4870 100         else if (strcasecmp(key, "ColMin") == 0)
931 485 50         self->colmin = (double)SvNV(val);
932 4385 100         else if (strcasecmp(key, "ComplexBreaking") == 0) {
933 358 100         if (SVtoboolean(val))
934 357           self->options |= LINEBREAK_OPTION_COMPLEX_BREAKING;
935             else
936 358           self->options &= ~LINEBREAK_OPTION_COMPLEX_BREAKING;
937 4027 100         } else if (strcasecmp(key, "Context") == 0) {
938 546 50         if (SvOK(val))
    0          
    0          
939 546 50         opt = (char *)SvPV_nolen(val);
940             else
941 0           opt = NULL;
942 546 50         if (opt && strcasecmp(opt, "EASTASIAN") == 0)
    100          
943 55           self->options |= LINEBREAK_OPTION_EASTASIAN_CONTEXT;
944             else
945 546           self->options &= ~LINEBREAK_OPTION_EASTASIAN_CONTEXT;
946 3481 100         } else if (strcasecmp(key, "EAWidth") == 0) {
947             AV *av, *codes;
948             SV *sv;
949             propval_t p;
950             size_t i;
951              
952 485 100         if (! SvOK(val))
    50          
    50          
953 357           linebreak_clear_eawidth(self);
954 128 50         else if (SvROK(val) &&
    50          
955 128 50         SvTYPE(av = (AV *)SvRV(val)) == SVt_PVAV &&
956 256 50         av_len(av) + 1 == 2 &&
957 256 50         av_fetch(av, 0, 0) != NULL && av_fetch(av, 1, 0) != NULL) {
958 128           sv = *av_fetch(av, 1, 0);
959 128 50         if (SvIOK(sv))
960 128 50         p = (propval_t) SvIV(sv);
961             else
962 0           croak("_config: Invalid argument");
963              
964 128           sv = *av_fetch(av, 0, 0);
965 256 50         if (SvROK(sv) &&
    50          
966 128           SvTYPE(codes = (AV *)SvRV(sv)) == SVt_PVAV) {
967 66084 100         for (i = 0; i < av_len(codes) + 1; i++) {
968 65956 50         if (av_fetch(codes, i, 0) == NULL)
969 0           continue;
970 65956 50         if (! SvIOK(sv = *av_fetch(codes, i, 0)))
971 0           croak("_config: Invalid argument");
972 131912 50         linebreak_update_eawidth(self,
973 65956           (unichar_t) SvUV(sv), p);
974             }
975 0 0         } else if (SvIOK(sv)) {
976 0 0         linebreak_update_eawidth(self, (unichar_t) SvUV(sv),
977             p);
978             } else
979 0           croak("_config: Invalid argument");
980             } else
981 485           croak("_config: Invalid argument");
982 2996 100         } else if (strcasecmp(key, "HangulAsAL") == 0) {
983 484 100         if (SVtoboolean(val))
984 1           self->options |= LINEBREAK_OPTION_HANGUL_AS_AL;
985             else
986 484           self->options &= ~LINEBREAK_OPTION_HANGUL_AS_AL;
987 2512 100         } else if (strcasecmp(key, "LBClass") == 0) {
988             AV *av, *codes;
989             SV *sv;
990             propval_t p;
991             size_t i;
992              
993 492 100         if (! SvOK(val))
    50          
    50          
994 483           linebreak_clear_lbclass(self);
995 9 50         else if (SvROK(val) &&
    50          
996 9 50         SvTYPE(av = (AV *)SvRV(val)) == SVt_PVAV &&
997 18 50         av_len(av) + 1 == 2 &&
998 18 50         av_fetch(av, 0, 0) != NULL && av_fetch(av, 1, 0) != NULL) {
999 9           sv = *av_fetch(av, 1, 0);
1000 9 50         if (SvIOK(sv))
1001 9 50         p = (propval_t) SvIV(sv);
1002             else
1003 0           croak("_config: Invalid argument");
1004              
1005 9           sv = *av_fetch(av, 0, 0);
1006 18 100         if (SvROK(sv) &&
    50          
1007 1           SvTYPE(codes = (AV *)SvRV(sv)) == SVt_PVAV) {
1008 59 100         for (i = 0; i < av_len(codes) + 1; i++) {
1009 58 50         if (av_fetch(codes, i, 0) == NULL)
1010 0           continue;
1011 58 50         if (! SvIOK(sv = *av_fetch(codes, i, 0)))
1012 0           croak("_config: Invalid argument");
1013 116 50         linebreak_update_lbclass(self,
1014 58           (unichar_t) SvUV(sv), p);
1015             }
1016 8 50         } else if (SvIOK(sv)) {
1017 8 50         linebreak_update_lbclass(self, (unichar_t) SvUV(sv),
1018             p);
1019             } else
1020 0           croak("_config: Invalid argument");
1021             } else
1022 492           croak("_config: Invalid argument");
1023 2020 100         } else if (strcasecmp(key, "LegacyCM") == 0) {
1024 832 100         if (SVtoboolean(val))
1025 831           self->options |= LINEBREAK_OPTION_LEGACY_CM;
1026             else
1027 832           self->options &= ~LINEBREAK_OPTION_LEGACY_CM;
1028 1188 100         } else if (strcasecmp(key, "Newline") == 0) {
1029 483 50         if (!sv_isobject(val)) {
1030 483           unistr_t unistr = {NULL, 0};
1031 483           SVtounistr(&unistr, val);
1032 483           linebreak_set_newline(self, &unistr);
1033 483           free(unistr.str);
1034 0 0         } else if (sv_derived_from(val, "Unicode::GCString"))
1035 0 0         linebreak_set_newline(self,
1036 0           (unistr_t *)PerltoC(gcstring_t *,
1037             val));
1038             else
1039 0 0         croak("_config: Unknown object %s",
    0          
1040 0 0         HvNAME(SvSTASH(SvRV(val))));
    0          
    0          
    0          
1041 705 50         } else if (strcasecmp(key, "ViramaAsJoiner") == 0) {
1042 705 100         if (SVtoboolean(val))
1043 357           self->options |= LINEBREAK_OPTION_VIRAMA_AS_JOINER;
1044             else
1045 705           self->options &= ~LINEBREAK_OPTION_VIRAMA_AS_JOINER;
1046             } else
1047 0           warn("_config: Setting unknown option %s", key);
1048             }
1049             OUTPUT:
1050             RETVAL
1051              
1052             void
1053             as_hashref(self, ...)
1054             linebreak_t *self;
1055             CODE:
1056 2971 50         if (self->stash == NULL)
1057 0           XSRETURN_UNDEF;
1058 2971           ST(0) = self->stash; /* should not be mortal */
1059 2971           XSRETURN(1);
1060              
1061             SV*
1062             as_scalarref(self, ...)
1063             linebreak_t *self;
1064             PREINIT:
1065             char buf[64];
1066             CODE:
1067 0           buf[0] = '\0';
1068 0 0         snprintf(buf, 64, "%s(0x%lx)", HvNAME(SvSTASH(SvRV(ST(0)))),
    0          
    0          
    0          
    0          
    0          
1069             (unsigned long)(void *)self);
1070 0           RETVAL = newRV_noinc(newSVpv(buf, 0));
1071             OUTPUT:
1072             RETVAL
1073              
1074             SV *
1075             as_string(self, ...)
1076             linebreak_t *self;
1077             PREINIT:
1078             char buf[64];
1079             CODE:
1080 0           buf[0] = '\0';
1081 0 0         snprintf(buf, 64, "%s(0x%lx)", HvNAME(SvSTASH(SvRV(ST(0)))),
    0          
    0          
    0          
    0          
    0          
1082             (unsigned long)(void *)self);
1083 0           RETVAL = newSVpv(buf, 0);
1084             OUTPUT:
1085             RETVAL
1086              
1087             propval_t
1088             lbrule(self, b_idx, a_idx)
1089             linebreak_t *self;
1090             propval_t b_idx;
1091             propval_t a_idx;
1092             PROTOTYPE: $$$
1093             CODE:
1094 0           warn("lbrule() is obsoleted. Use breakingRule()");
1095 0 0         if (!SvOK(ST(1)) || !SvOK(ST(2)))
    0          
    0          
    0          
    0          
    0          
1096 0           XSRETURN_UNDEF;
1097 0 0         if (self == NULL)
1098 0           XSRETURN_UNDEF;
1099 0           RETVAL = linebreak_get_lbrule(self, b_idx, a_idx);
1100 0 0         if (RETVAL == PROP_UNKNOWN)
1101 0           XSRETURN_UNDEF;
1102             OUTPUT:
1103             RETVAL
1104              
1105             propval_t
1106             breakingRule(lbobj, bgcstr, agcstr)
1107             linebreak_t *lbobj;
1108             generic_string bgcstr;
1109             generic_string agcstr;
1110             PROTOTYPE: $$$
1111             PREINIT:
1112             propval_t blbc, albc;
1113             CODE:
1114 18 50         if (!SvOK(ST(1)) || !SvOK(ST(2)))
    0          
    0          
    50          
    0          
    0          
1115 0           XSRETURN_UNDEF;
1116 18 50         if (lbobj == NULL)
1117 0           XSRETURN_UNDEF;
1118 18 50         if ((blbc = gcstring_lbclass_ext(bgcstr, -1)) == PROP_UNKNOWN)
1119 0           XSRETURN_UNDEF;
1120 18 50         if ((albc = gcstring_lbclass(agcstr, 0)) == PROP_UNKNOWN)
1121 0           XSRETURN_UNDEF;
1122 18           RETVAL = linebreak_get_lbrule(lbobj, blbc, albc);
1123 18 50         if (RETVAL == PROP_UNKNOWN)
1124 0           XSRETURN_UNDEF;
1125             OUTPUT:
1126             RETVAL
1127              
1128             void
1129             reset(self)
1130             linebreak_t *self;
1131             PROTOTYPE: $
1132             CODE:
1133 0           linebreak_reset(self);
1134              
1135             double
1136             strsize(lbobj, len, pre, spc, str, ...)
1137             linebreak_t *lbobj;
1138             double len;
1139             SV *pre;
1140             generic_string spc;
1141             generic_string str;
1142             PROTOTYPE: $$$$$;$
1143             CODE:
1144 0           warn("strsize() is obsoleted. Use Unicode::GCString::columns");
1145 0 0         if (5 < items)
1146 0           warn("``max'' argument of strsize was obsoleted");
1147              
1148 0           RETVAL = linebreak_sizing_UAX11(lbobj, len, NULL, spc, str);
1149 0 0         if (RETVAL == -1.0)
1150 0           croak("strsize: %s", strerror(lbobj->errnum));
1151             OUTPUT:
1152             RETVAL
1153              
1154             void
1155             break(self, input)
1156             linebreak_t *self;
1157             unistr_t *input;
1158             PROTOTYPE: $$
1159             PREINIT:
1160             gcstring_t **ret, *r;
1161             size_t i;
1162             PPCODE:
1163 6382 50         if (input == NULL)
1164 0           XSRETURN_UNDEF;
1165 6382           ret = linebreak_break(self, input);
1166              
1167 6382 100         if (ret == NULL) {
1168 2 50         if (self->errnum == LINEBREAK_EEXTN)
1169 0 0         croak("%s", SvPV_nolen(ERRSV));
    0          
    0          
    0          
1170 2 50         else if (self->errnum == LINEBREAK_ELONG)
1171 2           croak("%s", "Excessive line was found");
1172 0 0         else if (self->errnum)
1173 0           croak("%s", strerror(self->errnum));
1174             else
1175 0           croak("%s", "Unknown error");
1176             }
1177              
1178 6380 50         switch (GIMME_V) {
1179             case G_SCALAR:
1180 51           r = gcstring_new(NULL, self);
1181 1170 100         for (i = 0; ret[i] != NULL; i++)
1182 1119           gcstring_append(r, ret[i]);
1183 51           linebreak_free_result(ret, 1);
1184 51 50         XPUSHs(sv_2mortal(unistrtoSV((unistr_t *)r, 0, r->len)));
1185 51           gcstring_destroy(r);
1186 51           XSRETURN(1);
1187              
1188             case G_ARRAY:
1189 17128 100         for (i = 0; ret[i] != NULL; i++)
1190 10799 50         XPUSHs(sv_2mortal(CtoPerl("Unicode::GCString", ret[i])));
1191 6329           linebreak_free_result(ret, 0);
1192 6329           XSRETURN(i);
1193              
1194             default:
1195 0           linebreak_free_result(ret, 1);
1196 0           XSRETURN_EMPTY;
1197             }
1198              
1199             void
1200             break_partial(self, input)
1201             linebreak_t *self;
1202             unistr_t *input;
1203             PROTOTYPE: $$
1204             PREINIT:
1205             gcstring_t **ret, *r;
1206             size_t i;
1207             PPCODE:
1208 2346           ret = linebreak_break_partial(self, input);
1209              
1210 2346 50         if (ret == NULL) {
1211 0 0         if (self->errnum == LINEBREAK_EEXTN)
1212 0 0         croak("%s", SvPV_nolen(ERRSV));
    0          
    0          
    0          
1213 0 0         else if (self->errnum == LINEBREAK_ELONG)
1214 0           croak("%s", "Excessive line was found");
1215 0 0         else if (self->errnum)
1216 0           croak("%s", strerror(self->errnum));
1217             else
1218 0           croak("%s", "Unknown error");
1219             }
1220              
1221 2346 50         switch (GIMME_V) {
1222             case G_SCALAR:
1223 2346           r = gcstring_new(NULL, self);
1224 2640 100         for (i = 0; ret[i] != NULL; i++)
1225 294           gcstring_append(r, ret[i]);
1226 2346           linebreak_free_result(ret, 1);
1227 2346 50         XPUSHs(sv_2mortal(unistrtoSV((unistr_t *)r, 0, r->len)));
1228 2346           gcstring_destroy(r);
1229 2346           XSRETURN(1);
1230              
1231             case G_ARRAY:
1232 0 0         for (i = 0; ret[i] != NULL; i++)
1233 0 0         XPUSHs(sv_2mortal(CtoPerl("Unicode::GCString", ret[i])));
1234 0           linebreak_free_result(ret, 0);
1235 0           XSRETURN(i);
1236              
1237             default:
1238 0           linebreak_free_result(ret, 1);
1239 0           XSRETURN_EMPTY;
1240             }
1241              
1242             const char *
1243             UNICODE_VERSION()
1244             CODE:
1245 1           RETVAL = linebreak_unicode_version;
1246             OUTPUT:
1247             RETVAL
1248              
1249             const char *
1250             SOMBOK_VERSION()
1251             CODE:
1252 1           RETVAL = SOMBOK_VERSION;
1253             OUTPUT:
1254             RETVAL
1255              
1256              
1257             MODULE = Unicode::LineBreak PACKAGE = Unicode::LineBreak::SouthEastAsian
1258              
1259             const char *
1260             supported()
1261             PROTOTYPE:
1262             CODE:
1263 4           RETVAL = linebreak_southeastasian_supported;
1264 4 50         if (RETVAL == NULL)
1265 4           XSRETURN_UNDEF;
1266             OUTPUT:
1267             RETVAL
1268              
1269             MODULE = Unicode::LineBreak PACKAGE = Unicode::GCString
1270              
1271             gcstring_t *
1272             _new(klass, str, lbobj=NULL)
1273             char *klass;
1274             unistr_t *str;
1275             linebreak_t *lbobj;
1276             PROTOTYPE: $$;$
1277             CODE:
1278 416 50         if (str == NULL)
1279 0           XSRETURN_UNDEF;
1280             /* FIXME:buffer is copied twice. */
1281 416 50         if ((RETVAL = gcstring_newcopy(str, lbobj)) == NULL)
1282 0           croak("%s->_new: %s", klass, strerror(errno));
1283             OUTPUT:
1284             RETVAL
1285              
1286             void
1287             DESTROY(self)
1288             gcstring_t *self;
1289             PROTOTYPE: $
1290             CODE:
1291 39084           gcstring_destroy(self);
1292              
1293             void
1294             as_array(self)
1295             gcstring_t *self;
1296             PROTOTYPE: $
1297             PREINIT:
1298             size_t i;
1299             PPCODE:
1300 356 50         if (self != NULL)
1301 1045 100         for (i = 0; i < self->gclen; i++)
1302 689 50         XPUSHs(sv_2mortal(
1303             CtoPerl("Unicode::GCString",
1304             gcstring_substr(self, i, 1))));
1305              
1306             SV*
1307             as_scalarref(self, ...)
1308             gcstring_t *self;
1309             PREINIT:
1310             char buf[64];
1311             CODE:
1312 0           buf[0] = '\0';
1313 0 0         snprintf(buf, 64, "%s(0x%lx)", HvNAME(SvSTASH(SvRV(ST(0)))),
    0          
    0          
    0          
    0          
    0          
1314             (unsigned long)(void *)self);
1315 0           RETVAL = newRV_noinc(newSVpv(buf, 0));
1316             OUTPUT:
1317             RETVAL
1318              
1319             SV *
1320             as_string(self, ...)
1321             gcstring_t *self;
1322             PROTOTYPE: $;$;$
1323             CODE:
1324 11736           RETVAL = unistrtoSV((unistr_t *)self, 0, self->len);
1325             OUTPUT:
1326             RETVAL
1327              
1328             size_t
1329             chars(self)
1330             gcstring_t *self;
1331             PROTOTYPE: $
1332             CODE:
1333 5           RETVAL = self->len;
1334             OUTPUT:
1335             RETVAL
1336              
1337             #define lbobj self->lbobj
1338             int
1339             cmp(self, str, swap=FALSE)
1340             gcstring_t *self;
1341             generic_string str;
1342             swapspec_t swap;
1343             PROTOTYPE: $$;$
1344             CODE:
1345 1035 50         if (swap == TRUE)
1346 0           RETVAL = gcstring_cmp(str, self);
1347             else
1348 1035           RETVAL = gcstring_cmp(self, str);
1349             OUTPUT:
1350             RETVAL
1351              
1352             size_t
1353             columns(self)
1354             gcstring_t *self;
1355             CODE:
1356 3395           RETVAL = gcstring_columns(self);
1357             OUTPUT:
1358             RETVAL
1359              
1360             #define lbobj self->lbobj
1361             gcstring_t *
1362             concat(self, str, swap=FALSE)
1363             gcstring_t *self;
1364             generic_string str;
1365             swapspec_t swap;
1366             PROTOTYPE: $$;$
1367             CODE:
1368 2457 100         if (swap == TRUE)
1369 106           RETVAL = gcstring_concat(str, self);
1370 2351 100         else if (swap == -1) {
1371 9           gcstring_append(self, str);
1372 9           XSRETURN(1);
1373             } else
1374 2342           RETVAL = gcstring_concat(self, str);
1375             OUTPUT:
1376             RETVAL
1377              
1378             gcstring_t *
1379             copy(self)
1380             gcstring_t *self;
1381             PROTOTYPE: $
1382             CODE:
1383 1           RETVAL = gcstring_copy(self);
1384             OUTPUT:
1385             RETVAL
1386              
1387             int
1388             eos(self)
1389             gcstring_t *self;
1390             CODE:
1391 3344           RETVAL = gcstring_eos(self);
1392             OUTPUT:
1393             RETVAL
1394              
1395             unsigned int
1396             flag(self, ...)
1397             gcstring_t *self;
1398             PROTOTYPE: $;$;$
1399             PREINIT:
1400             int i;
1401             unsigned int flag;
1402             CODE:
1403 0           warn("flag() will be deprecated in near future");
1404 0 0         if (1 < items)
1405 0 0         i = SvIV(ST(1));
1406             else
1407 0           i = self->pos;
1408 0 0         if (i < 0 || self == NULL || self->gclen <= i)
    0          
    0          
1409 0           XSRETURN_UNDEF;
1410 0 0         if (2 < items) {
1411 0 0         flag = SvUV(ST(2));
1412 0 0         if (flag == (flag & 255))
1413 0           self->gcstr[i].flag = (unsigned char)flag;
1414             else
1415 0           warn("flag: unknown flag(s)");
1416             }
1417 0           RETVAL = (unsigned int)self->gcstr[i].flag;
1418             OUTPUT:
1419             RETVAL
1420              
1421             gcstring_t *
1422             item(self, ...)
1423             gcstring_t *self;
1424             PROTOTYPE: $;$
1425             PREINIT:
1426             int i;
1427             CODE:
1428 3311 50         if (1 < items)
1429 0 0         i = SvIV(ST(1));
1430             else
1431 3311           i = self->pos;
1432 3311 50         if (i < 0 || self == NULL || self->gclen <= i)
    50          
    50          
1433 0           XSRETURN_UNDEF;
1434              
1435 3311           RETVAL = gcstring_substr(self, i, 1);
1436             OUTPUT:
1437             RETVAL
1438              
1439             gcstring_t *
1440             join(self, ...)
1441             gcstring_t *self;
1442             PREINIT:
1443             size_t i;
1444             gcstring_t *str;
1445             CODE:
1446 0           switch (items) {
1447             case 0:
1448 0           croak("join: Too few arguments");
1449             case 1:
1450 0           RETVAL = gcstring_new(NULL, self->lbobj);
1451 0           break;
1452             case 2:
1453 0           RETVAL = SVtogcstring(ST(1), self->lbobj);
1454 0 0         if (sv_isobject(ST(1)))
1455 0           RETVAL = gcstring_copy(RETVAL);
1456 0           break;
1457             default:
1458 0           RETVAL = SVtogcstring(ST(1), self->lbobj);
1459 0 0         if (sv_isobject(ST(1)))
1460 0           RETVAL = gcstring_copy(RETVAL);
1461 0 0         for (i = 2; i < items; i++) {
1462 0           gcstring_append(RETVAL, self);
1463 0           str = SVtogcstring(ST(i), self->lbobj);
1464 0           gcstring_append(RETVAL, str);
1465 0 0         if (!sv_isobject(ST(i)))
1466 0           gcstring_destroy(str);
1467             }
1468 0           break;
1469             }
1470             OUTPUT:
1471             RETVAL
1472              
1473             propval_t
1474             lbc(self)
1475             gcstring_t *self;
1476             PROTOTYPE: $
1477             CODE:
1478 3365 50         if ((RETVAL = gcstring_lbclass(self, 0)) == PROP_UNKNOWN)
1479 0           XSRETURN_UNDEF;
1480             OUTPUT:
1481             RETVAL
1482              
1483             propval_t
1484             lbcext(self)
1485             gcstring_t *self;
1486             PROTOTYPE: $
1487             CODE:
1488 0 0         if ((RETVAL = gcstring_lbclass_ext(self, -1)) == PROP_UNKNOWN)
1489 0           XSRETURN_UNDEF;
1490             OUTPUT:
1491             RETVAL
1492              
1493             propval_t
1494             lbclass(self, ...)
1495             gcstring_t *self;
1496             PROTOTYPE: $;$
1497             PREINIT:
1498             int i;
1499             CODE:
1500 0           warn("lbclass() is obsoleted. Use lbc()");
1501 0 0         if (1 < items)
1502 0 0         i = SvIV(ST(1));
1503             else
1504 0           i = self->pos;
1505 0           RETVAL = gcstring_lbclass(self, i);
1506 0 0         if (RETVAL == PROP_UNKNOWN)
1507 0           XSRETURN_UNDEF;
1508             OUTPUT:
1509             RETVAL
1510              
1511             propval_t
1512             lbclass_ext(self, ...)
1513             gcstring_t *self;
1514             PROTOTYPE: $;$
1515             PREINIT:
1516             int i;
1517             CODE:
1518 0           warn("lbclass_ext() is obsoleted. Use lbcext()");
1519 0 0         if (1 < items)
1520 0 0         i = SvIV(ST(1));
1521             else
1522 0           i = self->pos;
1523 0           RETVAL = gcstring_lbclass_ext(self, i);
1524 0 0         if (RETVAL == PROP_UNKNOWN)
1525 0           XSRETURN_UNDEF;
1526             OUTPUT:
1527             RETVAL
1528              
1529             size_t
1530             length(self)
1531             gcstring_t *self;
1532             PROTOTYPE: $
1533             CODE:
1534 5           RETVAL = self->gclen;
1535             OUTPUT:
1536             RETVAL
1537              
1538             gcstring_t *
1539             next(self, ...)
1540             gcstring_t *self;
1541             PROTOTYPE: $;$;$
1542             PREINIT:
1543             gcchar_t *gc;
1544             CODE:
1545 1024 100         if (gcstring_eos(self))
1546 1           XSRETURN_UNDEF;
1547 1023           gc = gcstring_next(self);
1548 1023           RETVAL = gcstring_substr(self, gc - self->gcstr, 1);
1549             OUTPUT:
1550             RETVAL
1551              
1552             size_t
1553             pos(self, ...)
1554             gcstring_t *self;
1555             PROTOTYPE: $;$
1556             CODE:
1557 4656 100         if (1 < items)
1558 2328 50         gcstring_setpos(self, SvIV(ST(1)));
1559 4656           RETVAL = self->pos;
1560             OUTPUT:
1561             RETVAL
1562              
1563             #define lbobj self->lbobj
1564             gcstring_t *
1565             substr(self, offset, length=self->gclen, replacement=NULL)
1566             gcstring_t *self;
1567             int offset;
1568             int length;
1569             generic_string replacement;
1570             PROTOTYPE: $$;$;$
1571             CODE:
1572 2334           RETVAL = gcstring_substr(self, offset, length);
1573 2334 100         if (replacement != NULL)
1574 3 50         if (gcstring_replace(self, offset, length, replacement) == NULL)
1575 0           croak("substr: %s", strerror(errno));
1576 2334 50         if (RETVAL == NULL)
1577 0           croak("substr: %s", strerror(errno));
1578             OUTPUT:
1579             RETVAL
1580