maint: update copyright
[gnulib.git] / lib / unilbrk / u16-width-linebreaks.c
1 /* Line breaking of UTF-16 strings.
2    Copyright (C) 2001-2003, 2006-2014 Free Software Foundation, Inc.
3    Written by Bruno Haible <bruno@clisp.org>, 2001.
4
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.
9
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.
14
15    You should have received a copy of the GNU Lesser General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18 #include <config.h>
19
20 /* Specification.  */
21 #include "unilbrk.h"
22
23 #include "unistr.h"
24 #include "uniwidth.h"
25
26 int
27 u16_width_linebreaks (const uint16_t *s, size_t n,
28                       int width, int start_column, int at_end_columns,
29                       const char *o, const char *encoding,
30                       char *p)
31 {
32   const uint16_t *s_end;
33   char *last_p;
34   int last_column;
35   int piece_width;
36
37   u16_possible_linebreaks (s, n, encoding, p);
38
39   s_end = s + n;
40   last_p = NULL;
41   last_column = start_column;
42   piece_width = 0;
43   while (s < s_end)
44     {
45       ucs4_t uc;
46       int count = u16_mbtouc_unsafe (&uc, s, s_end - s);
47
48       /* Respect the override.  */
49       if (o != NULL && *o != UC_BREAK_UNDEFINED)
50         *p = *o;
51
52       if (*p == UC_BREAK_POSSIBLE || *p == UC_BREAK_MANDATORY)
53         {
54           /* An atomic piece of text ends here.  */
55           if (last_p != NULL && last_column + piece_width > width)
56             {
57               /* Insert a line break.  */
58               *last_p = UC_BREAK_POSSIBLE;
59               last_column = 0;
60             }
61         }
62
63       if (*p == UC_BREAK_MANDATORY)
64         {
65           /* uc is a line break character.  */
66           /* Start a new piece at column 0.  */
67           last_p = NULL;
68           last_column = 0;
69           piece_width = 0;
70         }
71       else
72         {
73           /* uc is not a line break character.  */
74           int w;
75
76           if (*p == UC_BREAK_POSSIBLE)
77             {
78               /* Start a new piece.  */
79               last_p = p;
80               last_column += piece_width;
81               piece_width = 0;
82               /* No line break for the moment, may be turned into
83                  UC_BREAK_POSSIBLE later, via last_p. */
84             }
85
86           *p = UC_BREAK_PROHIBITED;
87
88           w = uc_width (uc, encoding);
89           if (w >= 0) /* ignore control characters in the string */
90             piece_width += w;
91         }
92
93       s += count;
94       p += count;
95       if (o != NULL)
96         o += count;
97     }
98
99   /* The last atomic piece of text ends here.  */
100   if (last_p != NULL && last_column + piece_width + at_end_columns > width)
101     {
102       /* Insert a line break.  */
103       *last_p = UC_BREAK_POSSIBLE;
104       last_column = 0;
105     }
106
107   return last_column + piece_width;
108 }