1*5e7646d2SAndroid Build Coastguard Worker /*
2*5e7646d2SAndroid Build Coastguard Worker * Verify that translations in the .po file have the same number and type of
3*5e7646d2SAndroid Build Coastguard Worker * printf-style format strings.
4*5e7646d2SAndroid Build Coastguard Worker *
5*5e7646d2SAndroid Build Coastguard Worker * Copyright 2007-2017 by Apple Inc.
6*5e7646d2SAndroid Build Coastguard Worker * Copyright 1997-2007 by Easy Software Products, all rights reserved.
7*5e7646d2SAndroid Build Coastguard Worker *
8*5e7646d2SAndroid Build Coastguard Worker * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
9*5e7646d2SAndroid Build Coastguard Worker *
10*5e7646d2SAndroid Build Coastguard Worker * Usage:
11*5e7646d2SAndroid Build Coastguard Worker *
12*5e7646d2SAndroid Build Coastguard Worker * checkpo filename.{po,strings} [... filenameN.{po,strings}]
13*5e7646d2SAndroid Build Coastguard Worker *
14*5e7646d2SAndroid Build Coastguard Worker * Compile with:
15*5e7646d2SAndroid Build Coastguard Worker *
16*5e7646d2SAndroid Build Coastguard Worker * gcc -o checkpo checkpo.c `cups-config --libs`
17*5e7646d2SAndroid Build Coastguard Worker */
18*5e7646d2SAndroid Build Coastguard Worker
19*5e7646d2SAndroid Build Coastguard Worker #include <cups/cups-private.h>
20*5e7646d2SAndroid Build Coastguard Worker
21*5e7646d2SAndroid Build Coastguard Worker
22*5e7646d2SAndroid Build Coastguard Worker /*
23*5e7646d2SAndroid Build Coastguard Worker * Local functions...
24*5e7646d2SAndroid Build Coastguard Worker */
25*5e7646d2SAndroid Build Coastguard Worker
26*5e7646d2SAndroid Build Coastguard Worker static char *abbreviate(const char *s, char *buf, int bufsize);
27*5e7646d2SAndroid Build Coastguard Worker static cups_array_t *collect_formats(const char *id);
28*5e7646d2SAndroid Build Coastguard Worker static void free_formats(cups_array_t *fmts);
29*5e7646d2SAndroid Build Coastguard Worker
30*5e7646d2SAndroid Build Coastguard Worker
31*5e7646d2SAndroid Build Coastguard Worker /*
32*5e7646d2SAndroid Build Coastguard Worker * 'main()' - Validate .po and .strings files.
33*5e7646d2SAndroid Build Coastguard Worker */
34*5e7646d2SAndroid Build Coastguard Worker
35*5e7646d2SAndroid Build Coastguard Worker int /* O - Exit code */
main(int argc,char * argv[])36*5e7646d2SAndroid Build Coastguard Worker main(int argc, /* I - Number of command-line args */
37*5e7646d2SAndroid Build Coastguard Worker char *argv[]) /* I - Command-line arguments */
38*5e7646d2SAndroid Build Coastguard Worker {
39*5e7646d2SAndroid Build Coastguard Worker int i; /* Looping var */
40*5e7646d2SAndroid Build Coastguard Worker cups_array_t *po; /* .po file */
41*5e7646d2SAndroid Build Coastguard Worker _cups_message_t *msg; /* Current message */
42*5e7646d2SAndroid Build Coastguard Worker cups_array_t *idfmts, /* Format strings in msgid */
43*5e7646d2SAndroid Build Coastguard Worker *strfmts; /* Format strings in msgstr */
44*5e7646d2SAndroid Build Coastguard Worker char *idfmt, /* Current msgid format string */
45*5e7646d2SAndroid Build Coastguard Worker *strfmt; /* Current msgstr format string */
46*5e7646d2SAndroid Build Coastguard Worker int fmtidx; /* Format index */
47*5e7646d2SAndroid Build Coastguard Worker int status, /* Exit status */
48*5e7646d2SAndroid Build Coastguard Worker pass, /* Pass/fail status */
49*5e7646d2SAndroid Build Coastguard Worker untranslated; /* Untranslated messages */
50*5e7646d2SAndroid Build Coastguard Worker char idbuf[80], /* Abbreviated msgid */
51*5e7646d2SAndroid Build Coastguard Worker strbuf[80]; /* Abbreviated msgstr */
52*5e7646d2SAndroid Build Coastguard Worker
53*5e7646d2SAndroid Build Coastguard Worker
54*5e7646d2SAndroid Build Coastguard Worker if (argc < 2)
55*5e7646d2SAndroid Build Coastguard Worker {
56*5e7646d2SAndroid Build Coastguard Worker puts("Usage: checkpo filename.{po,strings} [... filenameN.{po,strings}]");
57*5e7646d2SAndroid Build Coastguard Worker return (1);
58*5e7646d2SAndroid Build Coastguard Worker }
59*5e7646d2SAndroid Build Coastguard Worker
60*5e7646d2SAndroid Build Coastguard Worker /*
61*5e7646d2SAndroid Build Coastguard Worker * Check every .po or .strings file on the command-line...
62*5e7646d2SAndroid Build Coastguard Worker */
63*5e7646d2SAndroid Build Coastguard Worker
64*5e7646d2SAndroid Build Coastguard Worker for (i = 1, status = 0; i < argc; i ++)
65*5e7646d2SAndroid Build Coastguard Worker {
66*5e7646d2SAndroid Build Coastguard Worker /*
67*5e7646d2SAndroid Build Coastguard Worker * Use the CUPS .po loader to get the message strings...
68*5e7646d2SAndroid Build Coastguard Worker */
69*5e7646d2SAndroid Build Coastguard Worker
70*5e7646d2SAndroid Build Coastguard Worker if (strstr(argv[i], ".strings"))
71*5e7646d2SAndroid Build Coastguard Worker po = _cupsMessageLoad(argv[i], _CUPS_MESSAGE_STRINGS);
72*5e7646d2SAndroid Build Coastguard Worker else
73*5e7646d2SAndroid Build Coastguard Worker po = _cupsMessageLoad(argv[i], _CUPS_MESSAGE_PO | _CUPS_MESSAGE_EMPTY);
74*5e7646d2SAndroid Build Coastguard Worker
75*5e7646d2SAndroid Build Coastguard Worker if (!po)
76*5e7646d2SAndroid Build Coastguard Worker {
77*5e7646d2SAndroid Build Coastguard Worker perror(argv[i]);
78*5e7646d2SAndroid Build Coastguard Worker return (1);
79*5e7646d2SAndroid Build Coastguard Worker }
80*5e7646d2SAndroid Build Coastguard Worker
81*5e7646d2SAndroid Build Coastguard Worker if (i > 1)
82*5e7646d2SAndroid Build Coastguard Worker putchar('\n');
83*5e7646d2SAndroid Build Coastguard Worker printf("%s: ", argv[i]);
84*5e7646d2SAndroid Build Coastguard Worker fflush(stdout);
85*5e7646d2SAndroid Build Coastguard Worker
86*5e7646d2SAndroid Build Coastguard Worker /*
87*5e7646d2SAndroid Build Coastguard Worker * Scan every message for a % string and then match them up with
88*5e7646d2SAndroid Build Coastguard Worker * the corresponding string in the translation...
89*5e7646d2SAndroid Build Coastguard Worker */
90*5e7646d2SAndroid Build Coastguard Worker
91*5e7646d2SAndroid Build Coastguard Worker pass = 1;
92*5e7646d2SAndroid Build Coastguard Worker untranslated = 0;
93*5e7646d2SAndroid Build Coastguard Worker
94*5e7646d2SAndroid Build Coastguard Worker for (msg = (_cups_message_t *)cupsArrayFirst(po);
95*5e7646d2SAndroid Build Coastguard Worker msg;
96*5e7646d2SAndroid Build Coastguard Worker msg = (_cups_message_t *)cupsArrayNext(po))
97*5e7646d2SAndroid Build Coastguard Worker {
98*5e7646d2SAndroid Build Coastguard Worker /*
99*5e7646d2SAndroid Build Coastguard Worker * Make sure filter message prefixes are not translated...
100*5e7646d2SAndroid Build Coastguard Worker */
101*5e7646d2SAndroid Build Coastguard Worker
102*5e7646d2SAndroid Build Coastguard Worker if (!strncmp(msg->msg, "ALERT:", 6) || !strncmp(msg->msg, "CRIT:", 5) ||
103*5e7646d2SAndroid Build Coastguard Worker !strncmp(msg->msg, "DEBUG:", 6) || !strncmp(msg->msg, "DEBUG2:", 7) ||
104*5e7646d2SAndroid Build Coastguard Worker !strncmp(msg->msg, "EMERG:", 6) || !strncmp(msg->msg, "ERROR:", 6) ||
105*5e7646d2SAndroid Build Coastguard Worker !strncmp(msg->msg, "INFO:", 5) || !strncmp(msg->msg, "NOTICE:", 7) ||
106*5e7646d2SAndroid Build Coastguard Worker !strncmp(msg->msg, "WARNING:", 8))
107*5e7646d2SAndroid Build Coastguard Worker {
108*5e7646d2SAndroid Build Coastguard Worker if (pass)
109*5e7646d2SAndroid Build Coastguard Worker {
110*5e7646d2SAndroid Build Coastguard Worker pass = 0;
111*5e7646d2SAndroid Build Coastguard Worker puts("FAIL");
112*5e7646d2SAndroid Build Coastguard Worker }
113*5e7646d2SAndroid Build Coastguard Worker
114*5e7646d2SAndroid Build Coastguard Worker printf(" Bad prefix on filter message \"%s\"\n",
115*5e7646d2SAndroid Build Coastguard Worker abbreviate(msg->msg, idbuf, sizeof(idbuf)));
116*5e7646d2SAndroid Build Coastguard Worker }
117*5e7646d2SAndroid Build Coastguard Worker
118*5e7646d2SAndroid Build Coastguard Worker idfmt = msg->msg + strlen(msg->msg) - 1;
119*5e7646d2SAndroid Build Coastguard Worker if (idfmt >= msg->msg && *idfmt == '\n')
120*5e7646d2SAndroid Build Coastguard Worker {
121*5e7646d2SAndroid Build Coastguard Worker if (pass)
122*5e7646d2SAndroid Build Coastguard Worker {
123*5e7646d2SAndroid Build Coastguard Worker pass = 0;
124*5e7646d2SAndroid Build Coastguard Worker puts("FAIL");
125*5e7646d2SAndroid Build Coastguard Worker }
126*5e7646d2SAndroid Build Coastguard Worker
127*5e7646d2SAndroid Build Coastguard Worker printf(" Trailing newline in message \"%s\"\n",
128*5e7646d2SAndroid Build Coastguard Worker abbreviate(msg->msg, idbuf, sizeof(idbuf)));
129*5e7646d2SAndroid Build Coastguard Worker }
130*5e7646d2SAndroid Build Coastguard Worker
131*5e7646d2SAndroid Build Coastguard Worker for (; idfmt >= msg->msg; idfmt --)
132*5e7646d2SAndroid Build Coastguard Worker if (!isspace(*idfmt & 255))
133*5e7646d2SAndroid Build Coastguard Worker break;
134*5e7646d2SAndroid Build Coastguard Worker
135*5e7646d2SAndroid Build Coastguard Worker if (idfmt >= msg->msg && *idfmt == '!')
136*5e7646d2SAndroid Build Coastguard Worker {
137*5e7646d2SAndroid Build Coastguard Worker if (pass)
138*5e7646d2SAndroid Build Coastguard Worker {
139*5e7646d2SAndroid Build Coastguard Worker pass = 0;
140*5e7646d2SAndroid Build Coastguard Worker puts("FAIL");
141*5e7646d2SAndroid Build Coastguard Worker }
142*5e7646d2SAndroid Build Coastguard Worker
143*5e7646d2SAndroid Build Coastguard Worker printf(" Exclamation in message \"%s\"\n",
144*5e7646d2SAndroid Build Coastguard Worker abbreviate(msg->msg, idbuf, sizeof(idbuf)));
145*5e7646d2SAndroid Build Coastguard Worker }
146*5e7646d2SAndroid Build Coastguard Worker
147*5e7646d2SAndroid Build Coastguard Worker if ((idfmt - 2) >= msg->msg && !strncmp(idfmt - 2, "...", 3))
148*5e7646d2SAndroid Build Coastguard Worker {
149*5e7646d2SAndroid Build Coastguard Worker if (pass)
150*5e7646d2SAndroid Build Coastguard Worker {
151*5e7646d2SAndroid Build Coastguard Worker pass = 0;
152*5e7646d2SAndroid Build Coastguard Worker puts("FAIL");
153*5e7646d2SAndroid Build Coastguard Worker }
154*5e7646d2SAndroid Build Coastguard Worker
155*5e7646d2SAndroid Build Coastguard Worker printf(" Ellipsis in message \"%s\"\n",
156*5e7646d2SAndroid Build Coastguard Worker abbreviate(msg->msg, idbuf, sizeof(idbuf)));
157*5e7646d2SAndroid Build Coastguard Worker }
158*5e7646d2SAndroid Build Coastguard Worker
159*5e7646d2SAndroid Build Coastguard Worker if (!msg->str || !msg->str[0])
160*5e7646d2SAndroid Build Coastguard Worker {
161*5e7646d2SAndroid Build Coastguard Worker untranslated ++;
162*5e7646d2SAndroid Build Coastguard Worker continue;
163*5e7646d2SAndroid Build Coastguard Worker }
164*5e7646d2SAndroid Build Coastguard Worker else if (strchr(msg->msg, '%'))
165*5e7646d2SAndroid Build Coastguard Worker {
166*5e7646d2SAndroid Build Coastguard Worker idfmts = collect_formats(msg->msg);
167*5e7646d2SAndroid Build Coastguard Worker strfmts = collect_formats(msg->str);
168*5e7646d2SAndroid Build Coastguard Worker fmtidx = 0;
169*5e7646d2SAndroid Build Coastguard Worker
170*5e7646d2SAndroid Build Coastguard Worker for (strfmt = (char *)cupsArrayFirst(strfmts);
171*5e7646d2SAndroid Build Coastguard Worker strfmt;
172*5e7646d2SAndroid Build Coastguard Worker strfmt = (char *)cupsArrayNext(strfmts))
173*5e7646d2SAndroid Build Coastguard Worker {
174*5e7646d2SAndroid Build Coastguard Worker if (isdigit(strfmt[1] & 255) && strfmt[2] == '$')
175*5e7646d2SAndroid Build Coastguard Worker {
176*5e7646d2SAndroid Build Coastguard Worker /*
177*5e7646d2SAndroid Build Coastguard Worker * Handle positioned format stuff...
178*5e7646d2SAndroid Build Coastguard Worker */
179*5e7646d2SAndroid Build Coastguard Worker
180*5e7646d2SAndroid Build Coastguard Worker fmtidx = strfmt[1] - '1';
181*5e7646d2SAndroid Build Coastguard Worker strfmt += 3;
182*5e7646d2SAndroid Build Coastguard Worker if ((idfmt = (char *)cupsArrayIndex(idfmts, fmtidx)) != NULL)
183*5e7646d2SAndroid Build Coastguard Worker idfmt ++;
184*5e7646d2SAndroid Build Coastguard Worker }
185*5e7646d2SAndroid Build Coastguard Worker else
186*5e7646d2SAndroid Build Coastguard Worker {
187*5e7646d2SAndroid Build Coastguard Worker /*
188*5e7646d2SAndroid Build Coastguard Worker * Compare against the current format...
189*5e7646d2SAndroid Build Coastguard Worker */
190*5e7646d2SAndroid Build Coastguard Worker
191*5e7646d2SAndroid Build Coastguard Worker idfmt = (char *)cupsArrayIndex(idfmts, fmtidx);
192*5e7646d2SAndroid Build Coastguard Worker }
193*5e7646d2SAndroid Build Coastguard Worker
194*5e7646d2SAndroid Build Coastguard Worker fmtidx ++;
195*5e7646d2SAndroid Build Coastguard Worker
196*5e7646d2SAndroid Build Coastguard Worker if (!idfmt || strcmp(strfmt, idfmt))
197*5e7646d2SAndroid Build Coastguard Worker break;
198*5e7646d2SAndroid Build Coastguard Worker }
199*5e7646d2SAndroid Build Coastguard Worker
200*5e7646d2SAndroid Build Coastguard Worker if (cupsArrayCount(strfmts) != cupsArrayCount(idfmts) || strfmt)
201*5e7646d2SAndroid Build Coastguard Worker {
202*5e7646d2SAndroid Build Coastguard Worker if (pass)
203*5e7646d2SAndroid Build Coastguard Worker {
204*5e7646d2SAndroid Build Coastguard Worker pass = 0;
205*5e7646d2SAndroid Build Coastguard Worker puts("FAIL");
206*5e7646d2SAndroid Build Coastguard Worker }
207*5e7646d2SAndroid Build Coastguard Worker
208*5e7646d2SAndroid Build Coastguard Worker printf(" Bad translation string \"%s\"\n for \"%s\"\n",
209*5e7646d2SAndroid Build Coastguard Worker abbreviate(msg->str, strbuf, sizeof(strbuf)),
210*5e7646d2SAndroid Build Coastguard Worker abbreviate(msg->msg, idbuf, sizeof(idbuf)));
211*5e7646d2SAndroid Build Coastguard Worker fputs(" Translation formats:", stdout);
212*5e7646d2SAndroid Build Coastguard Worker for (strfmt = (char *)cupsArrayFirst(strfmts);
213*5e7646d2SAndroid Build Coastguard Worker strfmt;
214*5e7646d2SAndroid Build Coastguard Worker strfmt = (char *)cupsArrayNext(strfmts))
215*5e7646d2SAndroid Build Coastguard Worker printf(" %s", strfmt);
216*5e7646d2SAndroid Build Coastguard Worker fputs("\n Original formats:", stdout);
217*5e7646d2SAndroid Build Coastguard Worker for (idfmt = (char *)cupsArrayFirst(idfmts);
218*5e7646d2SAndroid Build Coastguard Worker idfmt;
219*5e7646d2SAndroid Build Coastguard Worker idfmt = (char *)cupsArrayNext(idfmts))
220*5e7646d2SAndroid Build Coastguard Worker printf(" %s", idfmt);
221*5e7646d2SAndroid Build Coastguard Worker putchar('\n');
222*5e7646d2SAndroid Build Coastguard Worker putchar('\n');
223*5e7646d2SAndroid Build Coastguard Worker }
224*5e7646d2SAndroid Build Coastguard Worker
225*5e7646d2SAndroid Build Coastguard Worker free_formats(idfmts);
226*5e7646d2SAndroid Build Coastguard Worker free_formats(strfmts);
227*5e7646d2SAndroid Build Coastguard Worker }
228*5e7646d2SAndroid Build Coastguard Worker
229*5e7646d2SAndroid Build Coastguard Worker /*
230*5e7646d2SAndroid Build Coastguard Worker * Only allow \\, \n, \r, \t, \", and \### character escapes...
231*5e7646d2SAndroid Build Coastguard Worker */
232*5e7646d2SAndroid Build Coastguard Worker
233*5e7646d2SAndroid Build Coastguard Worker for (strfmt = msg->str; *strfmt; strfmt ++)
234*5e7646d2SAndroid Build Coastguard Worker {
235*5e7646d2SAndroid Build Coastguard Worker if (*strfmt == '\\')
236*5e7646d2SAndroid Build Coastguard Worker {
237*5e7646d2SAndroid Build Coastguard Worker strfmt ++;
238*5e7646d2SAndroid Build Coastguard Worker
239*5e7646d2SAndroid Build Coastguard Worker if (*strfmt != '\\' && *strfmt != 'n' && *strfmt != 'r' && *strfmt != 't' && *strfmt != '\"' && !isdigit(*strfmt & 255))
240*5e7646d2SAndroid Build Coastguard Worker {
241*5e7646d2SAndroid Build Coastguard Worker if (pass)
242*5e7646d2SAndroid Build Coastguard Worker {
243*5e7646d2SAndroid Build Coastguard Worker pass = 0;
244*5e7646d2SAndroid Build Coastguard Worker puts("FAIL");
245*5e7646d2SAndroid Build Coastguard Worker }
246*5e7646d2SAndroid Build Coastguard Worker
247*5e7646d2SAndroid Build Coastguard Worker printf(" Bad escape \\%c in filter message \"%s\"\n"
248*5e7646d2SAndroid Build Coastguard Worker " for \"%s\"\n", strfmt[1],
249*5e7646d2SAndroid Build Coastguard Worker abbreviate(msg->str, strbuf, sizeof(strbuf)),
250*5e7646d2SAndroid Build Coastguard Worker abbreviate(msg->msg, idbuf, sizeof(idbuf)));
251*5e7646d2SAndroid Build Coastguard Worker break;
252*5e7646d2SAndroid Build Coastguard Worker }
253*5e7646d2SAndroid Build Coastguard Worker }
254*5e7646d2SAndroid Build Coastguard Worker }
255*5e7646d2SAndroid Build Coastguard Worker }
256*5e7646d2SAndroid Build Coastguard Worker
257*5e7646d2SAndroid Build Coastguard Worker if (pass)
258*5e7646d2SAndroid Build Coastguard Worker {
259*5e7646d2SAndroid Build Coastguard Worker int count = cupsArrayCount(po); /* Total number of messages */
260*5e7646d2SAndroid Build Coastguard Worker
261*5e7646d2SAndroid Build Coastguard Worker if (untranslated >= (count / 10) && strcmp(argv[i], "cups.pot"))
262*5e7646d2SAndroid Build Coastguard Worker {
263*5e7646d2SAndroid Build Coastguard Worker /*
264*5e7646d2SAndroid Build Coastguard Worker * Only allow 10% of messages to be untranslated before we fail...
265*5e7646d2SAndroid Build Coastguard Worker */
266*5e7646d2SAndroid Build Coastguard Worker
267*5e7646d2SAndroid Build Coastguard Worker pass = 0;
268*5e7646d2SAndroid Build Coastguard Worker puts("FAIL");
269*5e7646d2SAndroid Build Coastguard Worker printf(" Too many untranslated messages (%d of %d or %.1f%% are translated)\n", count - untranslated, count, 100.0 - 100.0 * untranslated / count);
270*5e7646d2SAndroid Build Coastguard Worker }
271*5e7646d2SAndroid Build Coastguard Worker else if (untranslated > 0)
272*5e7646d2SAndroid Build Coastguard Worker printf("PASS (%d of %d or %.1f%% are translated)\n", count - untranslated, count, 100.0 - 100.0 * untranslated / count);
273*5e7646d2SAndroid Build Coastguard Worker else
274*5e7646d2SAndroid Build Coastguard Worker puts("PASS");
275*5e7646d2SAndroid Build Coastguard Worker }
276*5e7646d2SAndroid Build Coastguard Worker
277*5e7646d2SAndroid Build Coastguard Worker if (!pass)
278*5e7646d2SAndroid Build Coastguard Worker status = 1;
279*5e7646d2SAndroid Build Coastguard Worker
280*5e7646d2SAndroid Build Coastguard Worker _cupsMessageFree(po);
281*5e7646d2SAndroid Build Coastguard Worker }
282*5e7646d2SAndroid Build Coastguard Worker
283*5e7646d2SAndroid Build Coastguard Worker return (status);
284*5e7646d2SAndroid Build Coastguard Worker }
285*5e7646d2SAndroid Build Coastguard Worker
286*5e7646d2SAndroid Build Coastguard Worker
287*5e7646d2SAndroid Build Coastguard Worker /*
288*5e7646d2SAndroid Build Coastguard Worker * 'abbreviate()' - Abbreviate a message string as needed.
289*5e7646d2SAndroid Build Coastguard Worker */
290*5e7646d2SAndroid Build Coastguard Worker
291*5e7646d2SAndroid Build Coastguard Worker static char * /* O - Abbreviated string */
abbreviate(const char * s,char * buf,int bufsize)292*5e7646d2SAndroid Build Coastguard Worker abbreviate(const char *s, /* I - String to abbreviate */
293*5e7646d2SAndroid Build Coastguard Worker char *buf, /* I - Buffer */
294*5e7646d2SAndroid Build Coastguard Worker int bufsize) /* I - Size of buffer */
295*5e7646d2SAndroid Build Coastguard Worker {
296*5e7646d2SAndroid Build Coastguard Worker char *bufptr; /* Pointer into buffer */
297*5e7646d2SAndroid Build Coastguard Worker
298*5e7646d2SAndroid Build Coastguard Worker
299*5e7646d2SAndroid Build Coastguard Worker for (bufptr = buf, bufsize -= 4; *s && bufsize > 0; s ++)
300*5e7646d2SAndroid Build Coastguard Worker {
301*5e7646d2SAndroid Build Coastguard Worker if (*s == '\n')
302*5e7646d2SAndroid Build Coastguard Worker {
303*5e7646d2SAndroid Build Coastguard Worker if (bufsize < 2)
304*5e7646d2SAndroid Build Coastguard Worker break;
305*5e7646d2SAndroid Build Coastguard Worker
306*5e7646d2SAndroid Build Coastguard Worker *bufptr++ = '\\';
307*5e7646d2SAndroid Build Coastguard Worker *bufptr++ = 'n';
308*5e7646d2SAndroid Build Coastguard Worker bufsize -= 2;
309*5e7646d2SAndroid Build Coastguard Worker }
310*5e7646d2SAndroid Build Coastguard Worker else if (*s == '\t')
311*5e7646d2SAndroid Build Coastguard Worker {
312*5e7646d2SAndroid Build Coastguard Worker if (bufsize < 2)
313*5e7646d2SAndroid Build Coastguard Worker break;
314*5e7646d2SAndroid Build Coastguard Worker
315*5e7646d2SAndroid Build Coastguard Worker *bufptr++ = '\\';
316*5e7646d2SAndroid Build Coastguard Worker *bufptr++ = 't';
317*5e7646d2SAndroid Build Coastguard Worker bufsize -= 2;
318*5e7646d2SAndroid Build Coastguard Worker }
319*5e7646d2SAndroid Build Coastguard Worker else if (*s >= 0 && *s < ' ')
320*5e7646d2SAndroid Build Coastguard Worker {
321*5e7646d2SAndroid Build Coastguard Worker if (bufsize < 4)
322*5e7646d2SAndroid Build Coastguard Worker break;
323*5e7646d2SAndroid Build Coastguard Worker
324*5e7646d2SAndroid Build Coastguard Worker sprintf(bufptr, "\\%03o", *s);
325*5e7646d2SAndroid Build Coastguard Worker bufptr += 4;
326*5e7646d2SAndroid Build Coastguard Worker bufsize -= 4;
327*5e7646d2SAndroid Build Coastguard Worker }
328*5e7646d2SAndroid Build Coastguard Worker else
329*5e7646d2SAndroid Build Coastguard Worker {
330*5e7646d2SAndroid Build Coastguard Worker *bufptr++ = *s;
331*5e7646d2SAndroid Build Coastguard Worker bufsize --;
332*5e7646d2SAndroid Build Coastguard Worker }
333*5e7646d2SAndroid Build Coastguard Worker }
334*5e7646d2SAndroid Build Coastguard Worker
335*5e7646d2SAndroid Build Coastguard Worker if (*s)
336*5e7646d2SAndroid Build Coastguard Worker memcpy(bufptr, "...", 4);
337*5e7646d2SAndroid Build Coastguard Worker else
338*5e7646d2SAndroid Build Coastguard Worker *bufptr = '\0';
339*5e7646d2SAndroid Build Coastguard Worker
340*5e7646d2SAndroid Build Coastguard Worker return (buf);
341*5e7646d2SAndroid Build Coastguard Worker }
342*5e7646d2SAndroid Build Coastguard Worker
343*5e7646d2SAndroid Build Coastguard Worker
344*5e7646d2SAndroid Build Coastguard Worker /*
345*5e7646d2SAndroid Build Coastguard Worker * 'collect_formats()' - Collect all of the format strings in the msgid.
346*5e7646d2SAndroid Build Coastguard Worker */
347*5e7646d2SAndroid Build Coastguard Worker
348*5e7646d2SAndroid Build Coastguard Worker static cups_array_t * /* O - Array of format strings */
collect_formats(const char * id)349*5e7646d2SAndroid Build Coastguard Worker collect_formats(const char *id) /* I - msgid string */
350*5e7646d2SAndroid Build Coastguard Worker {
351*5e7646d2SAndroid Build Coastguard Worker cups_array_t *fmts; /* Array of format strings */
352*5e7646d2SAndroid Build Coastguard Worker char buf[255], /* Format string buffer */
353*5e7646d2SAndroid Build Coastguard Worker *bufptr; /* Pointer into format string */
354*5e7646d2SAndroid Build Coastguard Worker
355*5e7646d2SAndroid Build Coastguard Worker
356*5e7646d2SAndroid Build Coastguard Worker fmts = cupsArrayNew(NULL, NULL);
357*5e7646d2SAndroid Build Coastguard Worker
358*5e7646d2SAndroid Build Coastguard Worker while ((id = strchr(id, '%')) != NULL)
359*5e7646d2SAndroid Build Coastguard Worker {
360*5e7646d2SAndroid Build Coastguard Worker if (id[1] == '%')
361*5e7646d2SAndroid Build Coastguard Worker {
362*5e7646d2SAndroid Build Coastguard Worker /*
363*5e7646d2SAndroid Build Coastguard Worker * Skip %%...
364*5e7646d2SAndroid Build Coastguard Worker */
365*5e7646d2SAndroid Build Coastguard Worker
366*5e7646d2SAndroid Build Coastguard Worker id += 2;
367*5e7646d2SAndroid Build Coastguard Worker continue;
368*5e7646d2SAndroid Build Coastguard Worker }
369*5e7646d2SAndroid Build Coastguard Worker
370*5e7646d2SAndroid Build Coastguard Worker for (bufptr = buf; *id && bufptr < (buf + sizeof(buf) - 1); id ++)
371*5e7646d2SAndroid Build Coastguard Worker {
372*5e7646d2SAndroid Build Coastguard Worker *bufptr++ = *id;
373*5e7646d2SAndroid Build Coastguard Worker
374*5e7646d2SAndroid Build Coastguard Worker if (strchr("CDEFGIOSUXcdeifgopsux", *id))
375*5e7646d2SAndroid Build Coastguard Worker {
376*5e7646d2SAndroid Build Coastguard Worker id ++;
377*5e7646d2SAndroid Build Coastguard Worker break;
378*5e7646d2SAndroid Build Coastguard Worker }
379*5e7646d2SAndroid Build Coastguard Worker }
380*5e7646d2SAndroid Build Coastguard Worker
381*5e7646d2SAndroid Build Coastguard Worker *bufptr = '\0';
382*5e7646d2SAndroid Build Coastguard Worker cupsArrayAdd(fmts, strdup(buf));
383*5e7646d2SAndroid Build Coastguard Worker }
384*5e7646d2SAndroid Build Coastguard Worker
385*5e7646d2SAndroid Build Coastguard Worker return (fmts);
386*5e7646d2SAndroid Build Coastguard Worker }
387*5e7646d2SAndroid Build Coastguard Worker
388*5e7646d2SAndroid Build Coastguard Worker
389*5e7646d2SAndroid Build Coastguard Worker /*
390*5e7646d2SAndroid Build Coastguard Worker * 'free_formats()' - Free all of the format strings.
391*5e7646d2SAndroid Build Coastguard Worker */
392*5e7646d2SAndroid Build Coastguard Worker
393*5e7646d2SAndroid Build Coastguard Worker static void
free_formats(cups_array_t * fmts)394*5e7646d2SAndroid Build Coastguard Worker free_formats(cups_array_t *fmts) /* I - Array of format strings */
395*5e7646d2SAndroid Build Coastguard Worker {
396*5e7646d2SAndroid Build Coastguard Worker char *s; /* Current string */
397*5e7646d2SAndroid Build Coastguard Worker
398*5e7646d2SAndroid Build Coastguard Worker
399*5e7646d2SAndroid Build Coastguard Worker for (s = (char *)cupsArrayFirst(fmts); s; s = (char *)cupsArrayNext(fmts))
400*5e7646d2SAndroid Build Coastguard Worker free(s);
401*5e7646d2SAndroid Build Coastguard Worker
402*5e7646d2SAndroid Build Coastguard Worker cupsArrayDelete(fmts);
403*5e7646d2SAndroid Build Coastguard Worker }
404