]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/mdocml/preconv.c
Update elftoolchain to upstream rev 3130
[FreeBSD/FreeBSD.git] / contrib / mdocml / preconv.c
1 /*      $Id: preconv.c,v 1.12 2014/11/14 04:24:04 schwarze Exp $ */
2 /*
3  * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4  * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 #include "config.h"
19
20 #include <sys/types.h>
21
22 #include <stdio.h>
23 #include <string.h>
24 #include "mandoc.h"
25 #include "libmandoc.h"
26
27 int
28 preconv_encode(struct buf *ib, size_t *ii, struct buf *ob, size_t *oi,
29     int *filenc)
30 {
31         size_t           i;
32         int              state;
33         unsigned int     accum;
34         unsigned char    cu;
35
36         if ( ! (*filenc & MPARSE_UTF8))
37                 goto latin;
38
39         state = 0;
40         accum = 0U;
41
42         for (i = *ii; i < ib->sz; i++) {
43                 cu = ib->buf[i];
44                 if (state) {
45                         if ( ! (cu & 128) || (cu & 64)) {
46                                 /* Bad sequence header. */
47                                 break;
48                         }
49
50                         /* Accept only legitimate bit patterns. */
51
52                         if (cu > 191 || cu < 128) {
53                                 /* Bad in-sequence bits. */
54                                 break;
55                         }
56
57                         accum |= (cu & 63) << --state * 6;
58
59                         if (state)
60                                 continue;
61
62                         if (accum < 0x80)
63                                 ob->buf[(*oi)++] = accum;
64                         else
65                                 *oi += snprintf(ob->buf + *oi,
66                                     11, "\\[u%.4X]", accum);
67                         *ii = i + 1;
68                         *filenc &= ~MPARSE_LATIN1;
69                         return(1);
70                 } else {
71                         /*
72                          * Entering a UTF-8 state:  if we encounter a
73                          * UTF-8 bitmask, calculate the expected UTF-8
74                          * state from it.
75                          */
76                         for (state = 0; state < 7; state++)
77                                 if ( ! (cu & (1 << (7 - state))))
78                                         break;
79
80                         /* Accept only legitimate bit patterns. */
81
82                         switch (state--) {
83                         case (4):
84                                 if (cu <= 244 && cu >= 240) {
85                                         accum = (cu & 7) << 18;
86                                         continue;
87                                 }
88                                 /* Bad 4-sequence start bits. */
89                                 break;
90                         case (3):
91                                 if (cu <= 239 && cu >= 224) {
92                                         accum = (cu & 15) << 12;
93                                         continue;
94                                 }
95                                 /* Bad 3-sequence start bits. */
96                                 break;
97                         case (2):
98                                 if (cu <= 223 && cu >= 194) {
99                                         accum = (cu & 31) << 6;
100                                         continue;
101                                 }
102                                 /* Bad 2-sequence start bits. */
103                                 break;
104                         default:
105                                 /* Bad sequence bit mask. */
106                                 break;
107                         }
108                         break;
109                 }
110         }
111
112         /* FALLTHROUGH: Invalid or incomplete UTF-8 sequence. */
113
114 latin:
115         if ( ! (*filenc & MPARSE_LATIN1))
116                 return(0);
117
118         *oi += snprintf(ob->buf + *oi, 11,
119             "\\[u%.4X]", (unsigned char)ib->buf[(*ii)++]);
120
121         *filenc &= ~MPARSE_UTF8;
122         return(1);
123 }
124
125 int
126 preconv_cue(const struct buf *b, size_t offset)
127 {
128         const char      *ln, *eoln, *eoph;
129         size_t           sz, phsz;
130
131         ln = b->buf + offset;
132         sz = b->sz - offset;
133
134         /* Look for the end-of-line. */
135
136         if (NULL == (eoln = memchr(ln, '\n', sz)))
137                 eoln = ln + sz;
138
139         /* Check if we have the correct header/trailer. */
140
141         if ((sz = (size_t)(eoln - ln)) < 10 ||
142             memcmp(ln, ".\\\" -*-", 7) || memcmp(eoln - 3, "-*-", 3))
143                 return(MPARSE_UTF8 | MPARSE_LATIN1);
144
145         /* Move after the header and adjust for the trailer. */
146
147         ln += 7;
148         sz -= 10;
149
150         while (sz > 0) {
151                 while (sz > 0 && ' ' == *ln) {
152                         ln++;
153                         sz--;
154                 }
155                 if (0 == sz)
156                         break;
157
158                 /* Find the end-of-phrase marker (or eoln). */
159
160                 if (NULL == (eoph = memchr(ln, ';', sz)))
161                         eoph = eoln - 3;
162                 else
163                         eoph++;
164
165                 /* Only account for the "coding" phrase. */
166
167                 if ((phsz = eoph - ln) < 7 ||
168                     strncasecmp(ln, "coding:", 7)) {
169                         sz -= phsz;
170                         ln += phsz;
171                         continue;
172                 }
173
174                 sz -= 7;
175                 ln += 7;
176
177                 while (sz > 0 && ' ' == *ln) {
178                         ln++;
179                         sz--;
180                 }
181                 if (0 == sz)
182                         return(0);
183
184                 /* Check us against known encodings. */
185
186                 if (phsz > 4 && !strncasecmp(ln, "utf-8", 5))
187                         return(MPARSE_UTF8);
188                 if (phsz > 10 && !strncasecmp(ln, "iso-latin-1", 11))
189                         return(MPARSE_LATIN1);
190                 return(0);
191         }
192         return(MPARSE_UTF8 | MPARSE_LATIN1);
193 }