1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 2001 by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27 #include "sun_msgfmt.h"
28
29 static const char *mandatory_fields[] = {
30 "Project-Id-Version",
31 "PO-Revision-Date",
32 "Last-Translator",
33 "Language-Team",
34 "Content-Type",
35 "Content-Transfer-Encoding",
36 NULL
37 };
38
39 static const char *mandatory_fields_new[] = {
40 "POT-Creation-Date",
41 "Plural-Forms",
42 NULL
43 };
44
45 extern int verbose;
46
47 extern void invoke_gnu_msgfmt(void);
48
49 static size_t
get_one_line(char ** bufhead,char ** mbuf,size_t * fsize)50 get_one_line(char **bufhead, char **mbuf, size_t *fsize)
51 {
52 size_t len;
53 char *p = *mbuf;
54 char *q, *tmp;
55
56 if (*bufhead) {
57 free(*bufhead);
58 *bufhead = NULL;
59 }
60
61 if (*fsize == 0) {
62 /* eof */
63 return (0);
64 }
65
66 q = p;
67 while (((*fsize) != 0) && (*p++ != '\n')) {
68 (*fsize)--;
69 }
70 len = p - q;
71 if (len == 0) {
72 return (0);
73 }
74 tmp = (char *)Xmalloc(len + 1);
75 (void) memcpy(tmp, q, len);
76 tmp[len] = '\0';
77 *bufhead = tmp;
78 *mbuf = p;
79 return (len);
80 }
81
82 void
check_gnu(char * addr,size_t fsize)83 check_gnu(char *addr, size_t fsize)
84 {
85 int i;
86 char c, mc;
87 char *linebuf;
88 char *mbuf, *p, *buf;
89 unsigned int n;
90 size_t ln_size;
91 size_t bufsize, index;
92 size_t size = fsize;
93 int quotefound = 0;
94 const char *field;
95
96 buf = NULL;
97 linebuf = NULL;
98 mbuf = addr;
99
100 loop:
101 ln_size = get_one_line(&linebuf, &mbuf, &size);
102 if ((ln_size == (size_t)-1) ||
103 (ln_size == 0)) {
104 goto no_gnu;
105 }
106 p = linebuf;
107
108 while ((*p == '#') || (*p == '\n')) {
109 ln_size = get_one_line(&linebuf, &mbuf, &size);
110 if ((ln_size == (size_t)-1) ||
111 (ln_size == 0)) {
112 goto no_gnu;
113 }
114 p = linebuf;
115 }
116
117 if (strncmp(p, "domain", 6) == 0)
118 goto loop;
119
120 if (strncmp(p, "msgid", 5) != 0) {
121 /* error */
122 goto no_gnu;
123 }
124
125 p += 5;
126 if ((*p != ' ') && (*p != '\t') &&
127 (*p != '\n') && (*p != '\0')) {
128 /* no space after msgid */
129 goto no_gnu;
130 }
131 /* skip spaces */
132 while ((*p == ' ') || (*p == '\t'))
133 p++;
134
135 /* check if this entry is an empty string */
136 if ((*p != '\"') || (*(p + 1) != '\"')) {
137 /* this is not an empty string */
138 goto no_gnu;
139 }
140 p += 2;
141 while (*p && ((*p == ' ') || (*p == '\t'))) {
142 p++;
143 }
144 if ((*p != '\n') && (*p != '\0')) {
145 /* other characters than '\n' and '\0' found */
146 goto no_gnu;
147 }
148
149 for (; ; ) {
150 ln_size = get_one_line(&linebuf, &mbuf, &size);
151 if ((ln_size == (size_t)-1) ||
152 (ln_size == 0)) {
153 goto no_gnu;
154 }
155 p = linebuf;
156 /* skip leading spaces */
157 while ((*p == ' ') || (*p == '\t'))
158 p++;
159
160 if (*p != '\"') {
161 if (strncmp(p, "msgstr", 6) == 0) {
162 break;
163 }
164 /* not a valid entry */
165 goto no_gnu;
166 }
167 if (*(p + 1) != '\"') {
168 /* not an empty string */
169 goto no_gnu;
170 }
171 p += 2;
172 while ((*p == ' ') || (*p == '\t'))
173 p++;
174
175 if ((*p != '\n') && (*p != '\0')) {
176 /* other characters than '\n' and '\0' found */
177 goto no_gnu;
178 }
179 }
180
181 /*
182 * msgid for the header entry found
183 * Now p points to "msgstr"
184 */
185 p += 6;
186 if ((*p != ' ') && (*p != '\t') &&
187 (*p != '\n') && (*p != '\0')) {
188 /* no space after msgid */
189 goto no_gnu;
190 }
191
192 /* skip spaces */
193 while ((*p == ' ') || (*p == '\t'))
194 p++;
195
196 if (*p != '\"') {
197 /* no quote */
198 goto no_gnu;
199 }
200
201 bufsize = ln_size + 1;
202 index = 0;
203 buf = (char *)Xmalloc(bufsize);
204
205 for (; ; ) {
206 if (*p != '\"') {
207 /* msgstr entry ends */
208 buf[index] = '\0';
209 break;
210 }
211
212 if (*p++ != '\"') {
213 /* no beginning quote */
214 goto no_gnu;
215 }
216 while (*p) {
217 switch (mc = *p++) {
218 case '\n':
219 if (!quotefound) {
220 /* error */
221 goto no_gnu;
222 }
223 break;
224 case '\"':
225 quotefound = 1;
226 break;
227 case '\\':
228 if (!*p)
229 break;
230 switch (c = *p++) {
231 case 'b':
232 buf[index++] = '\b';
233 break;
234 case 'f':
235 buf[index++] = '\f';
236 break;
237 case 'n':
238 buf[index++] = '\n';
239 break;
240 case 'r':
241 buf[index++] = '\r';
242 break;
243 case 't':
244 buf[index++] = '\t';
245 break;
246 case 'v':
247 buf[index++] = '\v';
248 break;
249 case 'a':
250 buf[index++] = '\a';
251 break;
252 case '\"':
253 case '\\':
254 case '\'':
255 case '?':
256 buf[index++] = c;
257 break;
258 default:
259 if (isdigit((unsigned char)c)) {
260 unsigned int x;
261 unsigned char *up =
262 (unsigned char *)p;
263 n = c - '0';
264 if (isdigit(*up)) {
265 x = *up++ - '0';
266 n = 8 * n + x;
267 if (isdigit(*up)) {
268 x = *up++ - '0';
269 n = 8 * n + x;
270 }
271 }
272 p = (char *)up;
273 buf[index++] = n;
274 }
275 break;
276 }
277 break;
278 default:
279 buf[index++] = mc;
280 break;
281 }
282 if (quotefound) {
283 while (*p && ((*p == ' ') || (*p == '\t'))) {
284 p++;
285 }
286 if ((*p != '\n') && (*p != '\0')) {
287 goto no_gnu;
288 }
289 quotefound = 0;
290 break;
291 }
292 }
293 ln_size = get_one_line(&linebuf, &mbuf, &size);
294 if ((ln_size == (size_t)-1) ||
295 (ln_size == 0)) {
296 goto no_gnu;
297 }
298 p = linebuf;
299 /* skip spaces */
300 while ((*p == ' ') || (*p == '\t'))
301 p++;
302 bufsize += ln_size;
303 buf = (char *)Xrealloc(buf, bufsize);
304 }
305
306 for (i = 0; (field = mandatory_fields[i]) != NULL; i++) {
307 if (strstr(buf, field) == NULL)
308 continue;
309 /* one of mandatory fields found */
310 free(linebuf);
311 free(buf);
312 (void) munmap(addr, fsize);
313 if (verbose)
314 diag(gettext(DIAG_GNU_FOUND));
315 invoke_gnu_msgfmt();
316 /* NOTREACHED */
317 }
318 for (i = 0; (field = mandatory_fields_new[i]) != NULL; i++) {
319 if (strstr(buf, field) == NULL)
320 continue;
321 /* one of mandatory fields found */
322 free(linebuf);
323 free(buf);
324 (void) munmap(addr, fsize);
325 if (verbose)
326 diag(gettext(DIAG_GNU_FOUND));
327 invoke_gnu_msgfmt();
328 /* NOTREACHED */
329 }
330
331 no_gnu:
332 free(linebuf);
333 if (buf)
334 free(buf);
335 }
336