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