1 /*
2 * Localized printf/puts functions for CUPS.
3 *
4 * Copyright © 2020-2024 by OpenPrinting.
5 * Copyright 2007-2014 by Apple Inc.
6 * Copyright 2002-2007 by Easy Software Products.
7 *
8 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
9 */
10
11 /*
12 * Include necessary headers...
13 */
14
15 #include "cups-private.h"
16 #include "debug-internal.h"
17
18
19 /*
20 * '_cupsLangPrintError()' - Print a message followed by a standard error.
21 */
22
23 void
_cupsLangPrintError(const char * prefix,const char * message)24 _cupsLangPrintError(const char *prefix, /* I - Non-localized message prefix */
25 const char *message)/* I - Message */
26 {
27 ssize_t bytes; /* Number of bytes formatted */
28 int last_errno; /* Last error */
29 char buffer[2048], /* Message buffer */
30 *bufptr, /* Pointer into buffer */
31 output[8192]; /* Output buffer */
32 _cups_globals_t *cg; /* Global data */
33
34
35 /*
36 * Range check...
37 */
38
39 if (!message)
40 return;
41
42 /*
43 * Save the errno value...
44 */
45
46 last_errno = errno;
47
48 /*
49 * Get the message catalog...
50 */
51
52 cg = _cupsGlobals();
53
54 if (!cg->lang_default)
55 cg->lang_default = cupsLangDefault();
56
57 /*
58 * Format the message...
59 */
60
61 if (prefix)
62 {
63 snprintf(buffer, sizeof(buffer), "%s:", prefix);
64 bufptr = buffer + strlen(buffer);
65 }
66 else
67 bufptr = buffer;
68
69 snprintf(bufptr, sizeof(buffer) - (size_t)(bufptr - buffer),
70 /* TRANSLATORS: Message is "subject: error" */
71 _cupsLangString(cg->lang_default, _("%s: %s")),
72 _cupsLangString(cg->lang_default, message), strerror(last_errno));
73 strlcat(buffer, "\n", sizeof(buffer));
74
75 /*
76 * Convert and write to stderr...
77 */
78
79 bytes = cupsUTF8ToCharset(output, (cups_utf8_t *)buffer, sizeof(output),
80 cg->lang_default->encoding);
81
82 if (bytes > 0)
83 fwrite(output, 1, (size_t)bytes, stderr);
84 }
85
86
87 /*
88 * '_cupsLangPrintFilter()' - Print a formatted filter message string to a file.
89 */
90
91 int /* O - Number of bytes written */
_cupsLangPrintFilter(FILE * fp,const char * prefix,const char * message,...)92 _cupsLangPrintFilter(
93 FILE *fp, /* I - File to write to */
94 const char *prefix, /* I - Non-localized message prefix */
95 const char *message, /* I - Message string to use */
96 ...) /* I - Additional arguments as needed */
97 {
98 ssize_t bytes; /* Number of bytes formatted */
99 char temp[2048], /* Temporary format buffer */
100 buffer[2048], /* Message buffer */
101 output[8192]; /* Output buffer */
102 va_list ap; /* Pointer to additional arguments */
103 _cups_globals_t *cg; /* Global data */
104
105
106 /*
107 * Range check...
108 */
109
110 if (!fp || !message)
111 return (-1);
112
113 cg = _cupsGlobals();
114
115 if (!cg->lang_default)
116 cg->lang_default = cupsLangDefault();
117
118 /*
119 * Format the string...
120 */
121
122 va_start(ap, message);
123 snprintf(temp, sizeof(temp), "%s: %s\n", prefix,
124 _cupsLangString(cg->lang_default, message));
125 vsnprintf(buffer, sizeof(buffer), temp, ap);
126 va_end(ap);
127
128 /*
129 * Transcode to the destination charset...
130 */
131
132 bytes = cupsUTF8ToCharset(output, (cups_utf8_t *)buffer, sizeof(output),
133 cg->lang_default->encoding);
134
135 /*
136 * Write the string and return the number of bytes written...
137 */
138
139 if (bytes > 0)
140 return ((int)fwrite(output, 1, (size_t)bytes, fp));
141 else
142 return ((int)bytes);
143 }
144
145
146 /*
147 * '_cupsLangPrintf()' - Print a formatted message string to a file.
148 */
149
150 int /* O - Number of bytes written */
_cupsLangPrintf(FILE * fp,const char * message,...)151 _cupsLangPrintf(FILE *fp, /* I - File to write to */
152 const char *message, /* I - Message string to use */
153 ...) /* I - Additional arguments as needed */
154 {
155 ssize_t bytes; /* Number of bytes formatted */
156 char buffer[2048], /* Message buffer */
157 output[8192]; /* Output buffer */
158 va_list ap; /* Pointer to additional arguments */
159 _cups_globals_t *cg; /* Global data */
160
161
162 /*
163 * Range check...
164 */
165
166 if (!fp || !message)
167 return (-1);
168
169 cg = _cupsGlobals();
170
171 if (!cg->lang_default)
172 cg->lang_default = cupsLangDefault();
173
174 /*
175 * Format the string...
176 */
177
178 va_start(ap, message);
179 vsnprintf(buffer, sizeof(buffer) - 1,
180 _cupsLangString(cg->lang_default, message), ap);
181 va_end(ap);
182
183 strlcat(buffer, "\n", sizeof(buffer));
184
185 /*
186 * Transcode to the destination charset...
187 */
188
189 bytes = cupsUTF8ToCharset(output, (cups_utf8_t *)buffer, sizeof(output),
190 cg->lang_default->encoding);
191
192 /*
193 * Write the string and return the number of bytes written...
194 */
195
196 if (bytes > 0)
197 return ((int)fwrite(output, 1, (size_t)bytes, fp));
198 else
199 return ((int)bytes);
200 }
201
202
203 /*
204 * '_cupsLangPuts()' - Print a static message string to a file.
205 */
206
207 int /* O - Number of bytes written */
_cupsLangPuts(FILE * fp,const char * message)208 _cupsLangPuts(FILE *fp, /* I - File to write to */
209 const char *message) /* I - Message string to use */
210 {
211 ssize_t bytes; /* Number of bytes formatted */
212 char output[8192]; /* Message buffer */
213 _cups_globals_t *cg; /* Global data */
214
215
216 /*
217 * Range check...
218 */
219
220 if (!fp || !message)
221 return (-1);
222
223 cg = _cupsGlobals();
224
225 if (!cg->lang_default)
226 cg->lang_default = cupsLangDefault();
227
228 /*
229 * Transcode to the destination charset...
230 */
231
232 bytes = cupsUTF8ToCharset(output,
233 (cups_utf8_t *)_cupsLangString(cg->lang_default,
234 message),
235 sizeof(output) - 4, cg->lang_default->encoding);
236 bytes += cupsUTF8ToCharset(output + bytes, (cups_utf8_t *)"\n", (int)(sizeof(output) - (size_t)bytes), cg->lang_default->encoding);
237
238 /*
239 * Write the string and return the number of bytes written...
240 */
241
242 if (bytes > 0)
243 return ((int)fwrite(output, 1, (size_t)bytes, fp));
244 else
245 return ((int)bytes);
246 }
247
248
249 /*
250 * '_cupsSetLocale()' - Set the current locale and transcode the command-line.
251 */
252
253 void
_cupsSetLocale(char * argv[])254 _cupsSetLocale(char *argv[]) /* IO - Command-line arguments */
255 {
256 int i; /* Looping var */
257 char buffer[8192]; /* Command-line argument buffer */
258 _cups_globals_t *cg; /* Global data */
259 #ifdef LC_TIME
260 const char *lc_time; /* Current LC_TIME value */
261 char new_lc_time[255], /* New LC_TIME value */
262 *charset; /* Pointer to character set */
263 #endif /* LC_TIME */
264
265
266 /*
267 * Set the locale so that times, etc. are displayed properly.
268 *
269 * Unfortunately, while we need the localized time value, we *don't*
270 * want to use the localized charset for the time value, so we need
271 * to set LC_TIME to the locale name with .UTF-8 on the end (if
272 * the locale includes a character set specifier...)
273 */
274
275 setlocale(LC_ALL, "");
276
277 #ifdef LC_TIME
278 if ((lc_time = setlocale(LC_TIME, NULL)) == NULL)
279 lc_time = setlocale(LC_ALL, NULL);
280
281 if (lc_time)
282 {
283 strlcpy(new_lc_time, lc_time, sizeof(new_lc_time));
284 if ((charset = strchr(new_lc_time, '.')) == NULL)
285 charset = new_lc_time + strlen(new_lc_time);
286
287 strlcpy(charset, ".UTF-8", sizeof(new_lc_time) - (size_t)(charset - new_lc_time));
288 }
289 else
290 strlcpy(new_lc_time, "C", sizeof(new_lc_time));
291
292 setlocale(LC_TIME, new_lc_time);
293 #endif /* LC_TIME */
294
295 /*
296 * Initialize the default language info...
297 */
298
299 cg = _cupsGlobals();
300
301 if (!cg->lang_default)
302 cg->lang_default = cupsLangDefault();
303
304 /*
305 * Transcode the command-line arguments from the locale charset to
306 * UTF-8...
307 */
308
309 if (cg->lang_default->encoding != CUPS_US_ASCII &&
310 cg->lang_default->encoding != CUPS_UTF8)
311 {
312 for (i = 1; argv[i]; i ++)
313 {
314 /*
315 * Try converting from the locale charset to UTF-8...
316 */
317
318 if (cupsCharsetToUTF8((cups_utf8_t *)buffer, argv[i], sizeof(buffer),
319 cg->lang_default->encoding) < 0)
320 continue;
321
322 /*
323 * Save the new string if it differs from the original...
324 */
325
326 if (strcmp(buffer, argv[i]))
327 argv[i] = strdup(buffer);
328 }
329 }
330 }
331