]>
Commit | Line | Data |
---|---|---|
da5bb70a | 1 | /* |
c9d3f842 | 2 | * "$Id$" |
da5bb70a | 3 | * |
4 | * PPD model-specific attribute routines for the Common UNIX Printing System | |
5 | * (CUPS). | |
6 | * | |
571af0ea | 7 | * Copyright 2007-2009 by Apple Inc. |
91ac93ad | 8 | * Copyright 1997-2006 by Easy Software Products. |
da5bb70a | 9 | * |
10 | * These coded instructions, statements, and computer programs are the | |
4e8d321f | 11 | * property of Apple Inc. and are protected by Federal copyright |
12 | * law. Distribution and use rights are outlined in the file "LICENSE.txt" | |
13 | * which should have been included with this file. If this file is | |
14 | * file is missing or damaged, see the license at "http://www.cups.org/". | |
da5bb70a | 15 | * |
16 | * Contents: | |
17 | * | |
8f6753d3 | 18 | * ppdFindAttr() - Find the first matching attribute. |
19 | * ppdFindNextAttr() - Find the next matching attribute. | |
da5bb70a | 20 | */ |
21 | ||
22 | /* | |
23 | * Include necessary headers... | |
24 | */ | |
25 | ||
48845cc1 | 26 | #include "ppd-private.h" |
da5bb70a | 27 | #include "debug.h" |
28 | #include "string.h" | |
29 | #include <stdlib.h> | |
30 | ||
31 | ||
da5bb70a | 32 | /* |
8f6753d3 | 33 | * 'ppdFindAttr()' - Find the first matching attribute. |
0341722a | 34 | * |
373b3e5f | 35 | * @since CUPS 1.1.19/Mac OS X 10.3@ |
da5bb70a | 36 | */ |
37 | ||
8f6753d3 | 38 | ppd_attr_t * /* O - Attribute or @code NULL@ if not found */ |
51c4a398 | 39 | ppdFindAttr(ppd_file_t *ppd, /* I - PPD file data */ |
40 | const char *name, /* I - Attribute name */ | |
8f6753d3 | 41 | const char *spec) /* I - Specifier string or @code NULL@ */ |
da5bb70a | 42 | { |
51c4a398 | 43 | ppd_attr_t key, /* Search key */ |
44 | *attr; /* Current attribute */ | |
da5bb70a | 45 | |
46 | ||
571af0ea | 47 | DEBUG_printf(("2ppdFindAttr(ppd=%p, name=\"%s\", spec=\"%s\")", ppd, name, |
48 | spec)); | |
51c4a398 | 49 | |
da5bb70a | 50 | /* |
51 | * Range check input... | |
52 | */ | |
53 | ||
91ac93ad | 54 | if (!ppd || !name || ppd->num_attrs == 0) |
da5bb70a | 55 | return (NULL); |
56 | ||
57 | /* | |
91ac93ad | 58 | * Search for a matching attribute... |
da5bb70a | 59 | */ |
60 | ||
61 | memset(&key, 0, sizeof(key)); | |
91ac93ad | 62 | strlcpy(key.name, name, sizeof(key.name)); |
da5bb70a | 63 | |
64 | /* | |
91ac93ad | 65 | * Return the first matching attribute, if any... |
da5bb70a | 66 | */ |
67 | ||
51c4a398 | 68 | if ((attr = (ppd_attr_t *)cupsArrayFind(ppd->sorted_attrs, &key)) != NULL) |
51c4a398 | 69 | { |
85abd435 | 70 | if (spec) |
51c4a398 | 71 | { |
72 | /* | |
85abd435 | 73 | * Loop until we find the first matching attribute for "spec"... |
51c4a398 | 74 | */ |
75 | ||
85abd435 | 76 | while (attr && strcasecmp(spec, attr->spec)) |
77 | { | |
78 | if ((attr = (ppd_attr_t *)cupsArrayNext(ppd->sorted_attrs)) != NULL && | |
79 | strcasecmp(attr->name, name)) | |
80 | attr = NULL; | |
81 | } | |
51c4a398 | 82 | } |
83 | } | |
84 | ||
85 | return (attr); | |
da5bb70a | 86 | } |
87 | ||
88 | ||
89 | /* | |
8f6753d3 | 90 | * 'ppdFindNextAttr()' - Find the next matching attribute. |
0341722a | 91 | * |
373b3e5f | 92 | * @since CUPS 1.1.19/Mac OS X 10.3@ |
da5bb70a | 93 | */ |
94 | ||
8f6753d3 | 95 | ppd_attr_t * /* O - Attribute or @code NULL@ if not found */ |
da5bb70a | 96 | ppdFindNextAttr(ppd_file_t *ppd, /* I - PPD file data */ |
97 | const char *name, /* I - Attribute name */ | |
8f6753d3 | 98 | const char *spec) /* I - Specifier string or @code NULL@ */ |
da5bb70a | 99 | { |
91ac93ad | 100 | ppd_attr_t *attr; /* Current attribute */ |
da5bb70a | 101 | |
102 | ||
103 | /* | |
104 | * Range check input... | |
105 | */ | |
106 | ||
85abd435 | 107 | if (!ppd || !name || ppd->num_attrs == 0) |
da5bb70a | 108 | return (NULL); |
109 | ||
110 | /* | |
111 | * See if there are more attributes to return... | |
112 | */ | |
113 | ||
85abd435 | 114 | while ((attr = (ppd_attr_t *)cupsArrayNext(ppd->sorted_attrs)) != NULL) |
da5bb70a | 115 | { |
116 | /* | |
85abd435 | 117 | * Check the next attribute to see if it is a match... |
da5bb70a | 118 | */ |
119 | ||
85abd435 | 120 | if (strcasecmp(attr->name, name)) |
121 | { | |
122 | /* | |
123 | * Nope, reset the current pointer to the end of the array... | |
124 | */ | |
91ac93ad | 125 | |
85abd435 | 126 | cupsArrayIndex(ppd->sorted_attrs, cupsArrayCount(ppd->sorted_attrs)); |
127 | ||
128 | return (NULL); | |
129 | } | |
130 | ||
131 | if (!spec || !strcasecmp(attr->spec, spec)) | |
132 | break; | |
da5bb70a | 133 | } |
85abd435 | 134 | |
da5bb70a | 135 | /* |
136 | * Return the next attribute's value... | |
137 | */ | |
138 | ||
91ac93ad | 139 | return (attr); |
da5bb70a | 140 | } |
141 | ||
142 | ||
48845cc1 | 143 | /* |
144 | * '_ppdGet1284Values()' - Get 1284 device ID keys and values. | |
145 | * | |
146 | * The returned dictionary is a CUPS option array that can be queried with | |
147 | * cupsGetOption and freed with cupsFreeOptions. | |
148 | */ | |
149 | ||
150 | int /* O - Number of key/value pairs */ | |
151 | _ppdGet1284Values( | |
152 | const char *device_id, /* I - IEEE-1284 device ID string */ | |
153 | cups_option_t **values) /* O - Array of key/value pairs */ | |
154 | { | |
155 | int num_values; /* Number of values */ | |
156 | char key[256], /* Key string */ | |
157 | value[256], /* Value string */ | |
158 | *ptr; /* Pointer into key/value */ | |
159 | ||
160 | ||
161 | /* | |
162 | * Range check input... | |
163 | */ | |
164 | ||
165 | if (values) | |
166 | *values = NULL; | |
167 | ||
168 | if (!device_id || !values) | |
169 | return (0); | |
170 | ||
171 | /* | |
172 | * Parse the 1284 device ID value into keys and values. The format is | |
173 | * repeating sequences of: | |
174 | * | |
175 | * [whitespace]key:value[whitespace]; | |
176 | */ | |
177 | ||
178 | num_values = 0; | |
179 | while (*device_id) | |
180 | { | |
181 | while (isspace(*device_id & 255)) | |
182 | device_id ++; | |
183 | ||
184 | if (!*device_id) | |
185 | break; | |
186 | ||
187 | for (ptr = key; *device_id && *device_id != ':'; device_id ++) | |
188 | if (ptr < (key + sizeof(key) - 1)) | |
189 | *ptr++ = *device_id; | |
190 | ||
191 | if (!*device_id) | |
192 | break; | |
193 | ||
194 | while (ptr > key && isspace(ptr[-1] & 255)) | |
195 | ptr --; | |
196 | ||
197 | *ptr = '\0'; | |
198 | device_id ++; | |
199 | ||
200 | while (isspace(*device_id & 255)) | |
201 | device_id ++; | |
202 | ||
203 | if (!*device_id) | |
204 | break; | |
205 | ||
206 | for (ptr = value; *device_id && *device_id != ';'; device_id ++) | |
207 | if (ptr < (value + sizeof(value) - 1)) | |
208 | *ptr++ = *device_id; | |
209 | ||
210 | if (!*device_id) | |
211 | break; | |
212 | ||
213 | while (ptr > value && isspace(ptr[-1] & 255)) | |
214 | ptr --; | |
215 | ||
216 | *ptr = '\0'; | |
217 | device_id ++; | |
218 | ||
219 | num_values = cupsAddOption(key, value, num_values, values); | |
220 | } | |
221 | ||
222 | return (num_values); | |
223 | } | |
224 | ||
225 | ||
226 | /* | |
227 | * '_ppdNormalizeMakeAndModel()' - Normalize a product/make-and-model string. | |
228 | * | |
229 | * This function tries to undo the mistakes made by many printer manufacturers | |
230 | * to produce a clean make-and-model string we can use. | |
231 | */ | |
232 | ||
233 | char * /* O - Normalized make-and-model string or NULL on error */ | |
234 | _ppdNormalizeMakeAndModel( | |
235 | const char *make_and_model, /* I - Original make-and-model string */ | |
236 | char *buffer, /* I - String buffer */ | |
237 | size_t bufsize) /* I - Size of string buffer */ | |
238 | { | |
239 | char *bufptr; /* Pointer into buffer */ | |
240 | ||
241 | ||
242 | if (!make_and_model || !buffer || bufsize < 1) | |
243 | { | |
244 | if (buffer) | |
245 | *buffer = '\0'; | |
246 | ||
247 | return (NULL); | |
248 | } | |
249 | ||
250 | /* | |
251 | * Skip leading whitespace... | |
252 | */ | |
253 | ||
254 | while (isspace(*make_and_model & 255)) | |
255 | make_and_model ++; | |
256 | ||
257 | /* | |
258 | * Remove parenthesis and add manufacturers as needed... | |
259 | */ | |
260 | ||
261 | if (make_and_model[0] == '(') | |
262 | { | |
263 | strlcpy(buffer, make_and_model + 1, bufsize); | |
264 | ||
265 | if ((bufptr = strrchr(buffer, ')')) != NULL) | |
266 | *bufptr = '\0'; | |
267 | } | |
268 | else if (!strncasecmp(make_and_model, "XPrint", 6)) | |
269 | { | |
270 | /* | |
271 | * Xerox XPrint... | |
272 | */ | |
273 | ||
274 | snprintf(buffer, bufsize, "Xerox %s", make_and_model); | |
275 | } | |
276 | else if (!strncasecmp(make_and_model, "Eastman", 7)) | |
277 | { | |
278 | /* | |
279 | * Kodak... | |
280 | */ | |
281 | ||
282 | snprintf(buffer, bufsize, "Kodak %s", make_and_model + 7); | |
283 | } | |
284 | else if (!strncasecmp(make_and_model, "laserwriter", 11)) | |
285 | { | |
286 | /* | |
287 | * Apple LaserWriter... | |
288 | */ | |
289 | ||
290 | snprintf(buffer, bufsize, "Apple LaserWriter%s", make_and_model + 11); | |
291 | } | |
292 | else if (!strncasecmp(make_and_model, "colorpoint", 10)) | |
293 | { | |
294 | /* | |
295 | * Seiko... | |
296 | */ | |
297 | ||
298 | snprintf(buffer, bufsize, "Seiko %s", make_and_model); | |
299 | } | |
300 | else if (!strncasecmp(make_and_model, "fiery", 5)) | |
301 | { | |
302 | /* | |
303 | * EFI... | |
304 | */ | |
305 | ||
306 | snprintf(buffer, bufsize, "EFI %s", make_and_model); | |
307 | } | |
308 | else if (!strncasecmp(make_and_model, "ps ", 3) || | |
309 | !strncasecmp(make_and_model, "colorpass", 9)) | |
310 | { | |
311 | /* | |
312 | * Canon... | |
313 | */ | |
314 | ||
315 | snprintf(buffer, bufsize, "Canon %s", make_and_model); | |
316 | } | |
317 | else if (!strncasecmp(make_and_model, "primera", 7)) | |
318 | { | |
319 | /* | |
320 | * Fargo... | |
321 | */ | |
322 | ||
323 | snprintf(buffer, bufsize, "Fargo %s", make_and_model); | |
324 | } | |
325 | else if (!strncasecmp(make_and_model, "designjet", 9) || | |
326 | !strncasecmp(make_and_model, "deskjet", 7)) | |
327 | { | |
328 | /* | |
329 | * HP... | |
330 | */ | |
331 | ||
332 | snprintf(buffer, bufsize, "HP %s", make_and_model); | |
333 | } | |
334 | else | |
335 | strlcpy(buffer, make_and_model, bufsize); | |
336 | ||
337 | /* | |
338 | * Clean up the make... | |
339 | */ | |
340 | ||
341 | if (!strncasecmp(buffer, "agfa", 4)) | |
342 | { | |
343 | /* | |
344 | * Replace with AGFA (all uppercase)... | |
345 | */ | |
346 | ||
347 | buffer[0] = 'A'; | |
348 | buffer[1] = 'G'; | |
349 | buffer[2] = 'F'; | |
350 | buffer[3] = 'A'; | |
351 | } | |
352 | else if (!strncasecmp(buffer, "Hewlett-Packard hp ", 19)) | |
353 | { | |
354 | /* | |
355 | * Just put "HP" on the front... | |
356 | */ | |
357 | ||
358 | buffer[0] = 'H'; | |
359 | buffer[1] = 'P'; | |
360 | _cups_strcpy(buffer + 2, buffer + 18); | |
361 | } | |
362 | else if (!strncasecmp(buffer, "Hewlett-Packard ", 16)) | |
363 | { | |
364 | /* | |
365 | * Just put "HP" on the front... | |
366 | */ | |
367 | ||
368 | buffer[0] = 'H'; | |
369 | buffer[1] = 'P'; | |
370 | _cups_strcpy(buffer + 2, buffer + 15); | |
371 | } | |
372 | else if (!strncasecmp(buffer, "Lexmark International", 21)) | |
373 | { | |
374 | /* | |
375 | * Strip "International"... | |
376 | */ | |
377 | ||
378 | _cups_strcpy(buffer + 8, buffer + 21); | |
379 | } | |
380 | else if (!strncasecmp(buffer, "herk", 4)) | |
381 | { | |
382 | /* | |
383 | * Replace with LHAG... | |
384 | */ | |
385 | ||
386 | buffer[0] = 'L'; | |
387 | buffer[1] = 'H'; | |
388 | buffer[2] = 'A'; | |
389 | buffer[3] = 'G'; | |
390 | } | |
391 | else if (!strncasecmp(buffer, "linotype", 8)) | |
392 | { | |
393 | /* | |
394 | * Replace with LHAG... | |
395 | */ | |
396 | ||
397 | buffer[0] = 'L'; | |
398 | buffer[1] = 'H'; | |
399 | buffer[2] = 'A'; | |
400 | buffer[3] = 'G'; | |
401 | _cups_strcpy(buffer + 4, buffer + 8); | |
402 | } | |
403 | ||
404 | /* | |
405 | * Remove trailing whitespace and return... | |
406 | */ | |
407 | ||
408 | for (bufptr = buffer + strlen(buffer) - 1; | |
409 | bufptr >= buffer && isspace(*bufptr & 255); | |
410 | bufptr --); | |
411 | ||
412 | bufptr[1] = '\0'; | |
413 | ||
414 | return (buffer[0] ? buffer : NULL); | |
415 | } | |
416 | ||
417 | ||
da5bb70a | 418 | /* |
c9d3f842 | 419 | * End of "$Id$". |
da5bb70a | 420 | */ |