all: prefer https: URLs
[gnulib.git] / lib / unilbrk / u16-possible-linebreaks.c
blob413c98825852e6d8ef94e0c6cf93d4b1b1ae114f
1 /* Line breaking of UTF-16 strings.
2 Copyright (C) 2001-2003, 2006-2017 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2001.
5 This program is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Lesser General Public License as published
7 by the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18 #include <config.h>
20 /* Specification. */
21 #include "unilbrk.h"
23 #include <stdlib.h>
24 #include <string.h>
26 #include "unilbrk/lbrktables.h"
27 #include "uniwidth/cjk.h"
28 #include "unistr.h"
30 void
31 u16_possible_linebreaks (const uint16_t *s, size_t n, const char *encoding, char *p)
33 int LBP_AI_REPLACEMENT = (is_cjk_encoding (encoding) ? LBP_ID : LBP_AL);
34 const uint16_t *s_end = s + n;
35 int last_prop = LBP_BK; /* line break property of last non-space character */
36 char *seen_space = NULL; /* Was a space seen after the last non-space character? */
37 char *seen_space2 = NULL; /* At least two spaces after the last non-space? */
39 /* Don't break inside multibyte characters. */
40 memset (p, UC_BREAK_PROHIBITED, n);
42 while (s < s_end)
44 ucs4_t uc;
45 int count = u16_mbtouc_unsafe (&uc, s, s_end - s);
46 int prop = unilbrkprop_lookup (uc);
48 if (prop == LBP_BK)
50 /* Mandatory break. */
51 *p = UC_BREAK_MANDATORY;
52 last_prop = LBP_BK;
53 seen_space = NULL;
54 seen_space2 = NULL;
56 else
58 char *q;
60 /* Resolve property values whose behaviour is not fixed. */
61 switch (prop)
63 case LBP_AI:
64 /* Resolve ambiguous. */
65 prop = LBP_AI_REPLACEMENT;
66 break;
67 case LBP_CB:
68 /* This is arbitrary. */
69 prop = LBP_ID;
70 break;
71 case LBP_SA:
72 /* We don't handle complex scripts yet.
73 Treat LBP_SA like LBP_XX. */
74 case LBP_XX:
75 /* This is arbitrary. */
76 prop = LBP_AL;
77 break;
80 /* Deal with spaces and combining characters. */
81 q = p;
82 if (prop == LBP_SP)
84 /* Don't break just before a space. */
85 *p = UC_BREAK_PROHIBITED;
86 seen_space2 = seen_space;
87 seen_space = p;
89 else if (prop == LBP_ZW)
91 /* Don't break just before a zero-width space. */
92 *p = UC_BREAK_PROHIBITED;
93 last_prop = LBP_ZW;
94 seen_space = NULL;
95 seen_space2 = NULL;
97 else if (prop == LBP_CM)
99 /* Don't break just before a combining character, except immediately after a
100 zero-width space. */
101 if (last_prop == LBP_ZW)
103 /* Break after zero-width space. */
104 *p = UC_BREAK_POSSIBLE;
105 /* A combining character turns a preceding space into LBP_ID. */
106 last_prop = LBP_ID;
108 else
110 *p = UC_BREAK_PROHIBITED;
111 /* A combining character turns a preceding space into LBP_ID. */
112 if (seen_space != NULL)
114 q = seen_space;
115 seen_space = seen_space2;
116 prop = LBP_ID;
117 goto lookup_via_table;
121 else
123 lookup_via_table:
124 /* prop must be usable as an index for table 7.3 of UTR #14. */
125 if (!(prop >= 0 && prop < sizeof (unilbrk_table) / sizeof (unilbrk_table[0])))
126 abort ();
128 if (last_prop == LBP_BK)
130 /* Don't break at the beginning of a line. */
131 *q = UC_BREAK_PROHIBITED;
133 else if (last_prop == LBP_ZW)
135 /* Break after zero-width space. */
136 *q = UC_BREAK_POSSIBLE;
138 else
140 switch (unilbrk_table [last_prop] [prop])
142 case D:
143 *q = UC_BREAK_POSSIBLE;
144 break;
145 case I:
146 *q = (seen_space != NULL ? UC_BREAK_POSSIBLE : UC_BREAK_PROHIBITED);
147 break;
148 case P:
149 *q = UC_BREAK_PROHIBITED;
150 break;
151 default:
152 abort ();
155 last_prop = prop;
156 seen_space = NULL;
157 seen_space2 = NULL;
161 s += count;
162 p += count;