xref: /aosp_15_r20/external/libcups/locale/checkpo.c (revision 5e7646d21f1134fb0638875d812ef646c12ab91e)
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