]>
git.ipfire.org Git - thirdparty/cups.git/blob - cups/ppd.c
2 * "$Id: ppd.c,v 1.51.2.15 2002/05/16 13:59:59 mike Exp $"
4 * PPD file routines for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2002 by Easy Software Products, all rights reserved.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636-3111 USA
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
24 * PostScript is a trademark of Adobe Systems, Inc.
26 * This code and any derivative of it may be used and distributed
27 * freely under the terms of the GNU General Public License when
28 * used with GNU Ghostscript or its derivatives. Use of the code
29 * (or any derivative of it) with software other than GNU
30 * GhostScript (or its derivatives) is governed by the CUPS license
33 * This file is subject to the Apple OS-Developed Software exception.
37 * ppdClose() - Free all memory used by the PPD file.
38 * ppd_free_group() - Free a single UI group.
39 * ppd_free_option() - Free a single option.
40 * ppdOpen() - Read a PPD file into memory.
41 * ppdOpenFd() - Read a PPD file into memory.
42 * ppdOpenFile() - Read a PPD file into memory.
43 * ppd_read() - Read a line from a PPD file, skipping comment lines
45 * compare_strings() - Compare two strings.
46 * compare_groups() - Compare two groups.
47 * compare_options() - Compare two options.
48 * compare_choices() - Compare two choices.
52 * Include necessary headers.
67 #if defined(WIN32) || defined(__EMX__)
68 # define READ_BINARY "rb" /* Open a binary file for reading */
69 # define WRITE_BINARY "wb" /* Open a binary file for writing */
71 # define READ_BINARY "r" /* Open a binary file for reading */
72 # define WRITE_BINARY "w" /* Open a binary file for writing */
73 #endif /* WIN32 || __EMX__ */
75 #define safe_free(p) if (p) free(p) /* Safe free macro */
77 #define PPD_KEYWORD 1 /* Line contained a keyword */
78 #define PPD_OPTION 2 /* Line contained an option name */
79 #define PPD_TEXT 4 /* Line contained human-readable text */
80 #define PPD_STRING 8 /* Line contained a string or code */
87 static int compare_strings(char *s
, char *t
);
88 static int compare_groups(ppd_group_t
*g0
, ppd_group_t
*g1
);
89 static int compare_options(ppd_option_t
*o0
, ppd_option_t
*o1
);
90 static int compare_choices(ppd_choice_t
*c0
, ppd_choice_t
*c1
);
91 static int ppd_read(FILE *fp
, char *keyword
, char *option
,
92 char *text
, char **string
);
93 static void ppd_decode(char *string
);
94 static void ppd_fix(char *string
);
95 static void ppd_free_group(ppd_group_t
*group
);
96 static void ppd_free_option(ppd_option_t
*option
);
97 static ppd_group_t
*ppd_get_group(ppd_file_t
*ppd
, const char *name
,
99 static ppd_attr_t
*ppd_add_attr(ppd_file_t
*ppd
, const char *name
,
100 const char *spec
, const char *value
);
101 static ppd_option_t
*ppd_get_option(ppd_group_t
*group
, const char *name
);
102 static ppd_choice_t
*ppd_add_choice(ppd_option_t
*option
, const char *name
);
106 * 'ppdClose()' - Free all memory used by the PPD file.
110 ppdClose(ppd_file_t
*ppd
) /* I - PPD file record */
112 int i
; /* Looping var */
113 ppd_emul_t
*emul
; /* Current emulation */
114 ppd_group_t
*group
; /* Current group */
115 char **font
; /* Current font */
116 char **filter
; /* Current filter */
117 ppd_attr_t
**attr
; /* Current attribute */
121 * Range check the PPD file record...
128 * Free all strings at the top level...
131 safe_free(ppd
->patches
);
132 safe_free(ppd
->jcl_begin
);
133 safe_free(ppd
->jcl_ps
);
134 safe_free(ppd
->jcl_end
);
135 safe_free(ppd
->lang_encoding
);
136 safe_free(ppd
->lang_version
);
137 safe_free(ppd
->modelname
);
138 safe_free(ppd
->ttrasterizer
);
139 safe_free(ppd
->manufacturer
);
140 safe_free(ppd
->product
);
141 safe_free(ppd
->nickname
);
142 safe_free(ppd
->shortnickname
);
145 * Free any emulations...
148 if (ppd
->num_emulations
> 0)
150 for (i
= ppd
->num_emulations
, emul
= ppd
->emulations
; i
> 0; i
--, emul
++)
152 safe_free(emul
->start
);
153 safe_free(emul
->stop
);
156 safe_free(ppd
->emulations
);
160 * Free any UI groups, subgroups, and options...
163 if (ppd
->num_groups
> 0)
165 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
166 ppd_free_group(group
);
168 safe_free(ppd
->groups
);
172 * Free any page sizes...
175 if (ppd
->num_sizes
> 0)
176 safe_free(ppd
->sizes
);
179 * Free any constraints...
182 if (ppd
->num_consts
> 0)
183 safe_free(ppd
->consts
);
186 * Free any filters...
189 if (ppd
->num_filters
> 0)
191 for (i
= ppd
->num_filters
, filter
= ppd
->filters
; i
> 0; i
--, filter
++)
194 safe_free(ppd
->filters
);
201 if (ppd
->num_fonts
> 0)
203 for (i
= ppd
->num_fonts
, font
= ppd
->fonts
; i
> 0; i
--, font
++)
206 safe_free(ppd
->fonts
);
210 * Free any profiles...
213 if (ppd
->num_profiles
> 0)
214 safe_free(ppd
->profiles
);
217 * Free any attributes...
220 if (ppd
->num_attrs
> 0)
222 for (i
= ppd
->num_attrs
, attr
= ppd
->attrs
; i
> 0; i
--, attr
++)
224 safe_free((*attr
)->value
);
228 safe_free(ppd
->attrs
);
232 * Free the whole record...
240 * 'ppd_add_attr()' - Add an attribute to the PPD data.
243 static ppd_attr_t
* /* O - New attribute */
244 ppd_add_attr(ppd_file_t
*ppd
, /* I - PPD file data */
245 const char *name
, /* I - Attribute name */
246 const char *spec
, /* I - Specifier string, if any */
247 const char *value
) /* I - Value of attribute */
249 ppd_attr_t
**ptr
, /* New array */
250 *temp
; /* New attribute */
254 * Range check input...
257 if (ppd
== NULL
|| name
== NULL
|| spec
== NULL
)
261 * Allocate memory for the new attribute...
264 if (ppd
->num_attrs
== 0)
265 ptr
= malloc(sizeof(ppd_attr_t
*));
267 ptr
= realloc(ppd
->attrs
, (ppd
->num_attrs
+ 1) * sizeof(ppd_attr_t
*));
273 ptr
+= ppd
->num_attrs
;
275 if ((temp
= calloc(1, sizeof(ppd_attr_t
))) == NULL
)
286 strlcpy(temp
->name
, name
, sizeof(temp
->name
));
287 strlcpy(temp
->spec
, spec
, sizeof(temp
->spec
));
288 temp
->value
= (char *)value
;
291 * Return the attribute...
299 * '_ppd_attr_compare()' - Compare two attributes.
302 int /* O - Result of comparison */
303 _ppd_attr_compare(ppd_attr_t
**a
, /* I - First attribute */
304 ppd_attr_t
**b
) /* I - Second attribute */
306 int ret
; /* Result of comparison */
309 if ((ret
= strcasecmp((*a
)->name
, (*b
)->name
)) != 0)
311 else if ((*a
)->spec
[0] && (*b
)->spec
[0])
312 return (strcasecmp((*a
)->spec
, (*b
)->spec
));
319 * 'ppd_free_group()' - Free a single UI group.
323 ppd_free_group(ppd_group_t
*group
) /* I - Group to free */
325 int i
; /* Looping var */
326 ppd_option_t
*option
; /* Current option */
327 ppd_group_t
*subgroup
; /* Current sub-group */
330 if (group
->num_options
> 0)
332 for (i
= group
->num_options
, option
= group
->options
;
335 ppd_free_option(option
);
337 safe_free(group
->options
);
340 if (group
->num_subgroups
> 0)
342 for (i
= group
->num_subgroups
, subgroup
= group
->subgroups
;
345 ppd_free_group(subgroup
);
347 safe_free(group
->subgroups
);
353 * 'ppd_free_option()' - Free a single option.
357 ppd_free_option(ppd_option_t
*option
) /* I - Option to free */
359 int i
; /* Looping var */
360 ppd_choice_t
*choice
; /* Current choice */
363 if (option
->num_choices
> 0)
365 for (i
= option
->num_choices
, choice
= option
->choices
;
368 safe_free(choice
->code
);
370 safe_free(option
->choices
);
376 * 'ppd_get_group()' - Find or create the named group as needed.
379 static ppd_group_t
* /* O - Named group */
380 ppd_get_group(ppd_file_t
*ppd
, /* I - PPD file */
381 const char *name
, /* I - Name of group */
382 const char *text
) /* I - Text for group */
384 int i
; /* Looping var */
385 ppd_group_t
*group
; /* Group */
388 DEBUG_printf(("ppd_get_group(%p, \"%s\")\n", ppd
, name
));
390 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
391 if (strcmp(group
->name
, name
) == 0)
396 DEBUG_printf(("Adding group %s...\n", name
));
398 if (ppd
->num_groups
== 0)
399 group
= malloc(sizeof(ppd_group_t
));
401 group
= realloc(ppd
->groups
,
402 (ppd
->num_groups
+ 1) * sizeof(ppd_group_t
));
408 group
+= ppd
->num_groups
;
411 memset(group
, 0, sizeof(ppd_group_t
));
412 strlcpy(group
->name
, name
, sizeof(group
->name
));
413 strlcpy(group
->text
, text
, sizeof(group
->text
));
421 * 'ppd_get_option()' - Find or create the named option as needed.
424 static ppd_option_t
* /* O - Named option */
425 ppd_get_option(ppd_group_t
*group
, /* I - Group */
426 const char *name
) /* I - Name of option */
428 int i
; /* Looping var */
429 ppd_option_t
*option
; /* Option */
432 for (i
= group
->num_options
, option
= group
->options
; i
> 0; i
--, option
++)
433 if (strcmp(option
->keyword
, name
) == 0)
438 if (group
->num_options
== 0)
439 option
= malloc(sizeof(ppd_option_t
));
441 option
= realloc(group
->options
,
442 (group
->num_options
+ 1) * sizeof(ppd_option_t
));
447 group
->options
= option
;
448 option
+= group
->num_options
;
449 group
->num_options
++;
451 memset(option
, 0, sizeof(ppd_option_t
));
452 strlcpy(option
->keyword
, name
, sizeof(option
->keyword
));
460 * 'ppd_add_choice()' - Add a choice to an option.
463 static ppd_choice_t
* /* O - Named choice */
464 ppd_add_choice(ppd_option_t
*option
, /* I - Option */
465 const char *name
) /* I - Name of choice */
467 ppd_choice_t
*choice
; /* Choice */
470 if (option
->num_choices
== 0)
471 choice
= malloc(sizeof(ppd_choice_t
));
473 choice
= realloc(option
->choices
,
474 sizeof(ppd_choice_t
) * (option
->num_choices
+ 1));
479 option
->choices
= choice
;
480 choice
+= option
->num_choices
;
481 option
->num_choices
++;
483 memset(choice
, 0, sizeof(ppd_choice_t
));
484 strlcpy(choice
->choice
, name
, sizeof(choice
->choice
));
491 * 'ppd_add_size()' - Add a page size.
494 static ppd_size_t
* /* O - Named size */
495 ppd_add_size(ppd_file_t
*ppd
, /* I - PPD file */
496 const char *name
) /* I - Name of size */
498 ppd_size_t
*size
; /* Size */
501 if (ppd
->num_sizes
== 0)
502 size
= malloc(sizeof(ppd_size_t
));
504 size
= realloc(ppd
->sizes
, sizeof(ppd_size_t
) * (ppd
->num_sizes
+ 1));
510 size
+= ppd
->num_sizes
;
513 memset(size
, 0, sizeof(ppd_size_t
));
514 strlcpy(size
->name
, name
, sizeof(size
->name
));
521 * 'ppdOpen()' - Read a PPD file into memory.
524 ppd_file_t
* /* O - PPD file record */
525 ppdOpen(FILE *fp
) /* I - File to read from */
527 int i
, j
, k
, m
; /* Looping vars */
528 int count
; /* Temporary count */
529 ppd_file_t
*ppd
; /* PPD file record */
530 ppd_group_t
*group
, /* Current group */
531 *subgroup
; /* Current sub-group */
532 ppd_option_t
*option
; /* Current option */
533 ppd_choice_t
*choice
; /* Current choice */
534 ppd_const_t
*constraint
; /* Current constraint */
535 ppd_size_t
*size
; /* Current page size */
536 int mask
; /* Line data mask */
537 char keyword
[PPD_MAX_NAME
],
538 /* Keyword from file */
540 /* Option from file */
542 /* Human-readable text from file */
543 *string
, /* Code/text from file */
544 *sptr
, /* Pointer into string */
545 *nameptr
, /* Pointer into name */
546 *temp
, /* Temporary string pointer */
547 **tempfonts
; /* Temporary fonts pointer */
548 float order
; /* Order dependency number */
549 ppd_section_t section
; /* Order dependency section */
550 ppd_profile_t
*profile
; /* Pointer to color profile */
551 char **filter
; /* Pointer to filter */
552 cups_lang_t
*language
; /* Default language */
556 * Get the default language for the user...
559 language
= cupsLangDefault();
562 * Range check input...
569 * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
572 mask
= ppd_read(fp
, keyword
, name
, text
, &string
);
575 strcmp(keyword
, "PPD-Adobe") != 0 ||
576 string
== NULL
|| string
[0] != '4')
579 * Either this is not a PPD file, or it is not a 4.x PPD file.
587 DEBUG_printf(("ppdOpen: keyword = %s, string = %p\n", keyword
, string
));
592 * Allocate memory for the PPD file record...
595 if ((ppd
= calloc(sizeof(ppd_file_t
), 1)) == NULL
)
598 ppd
->language_level
= 1;
599 ppd
->color_device
= 0;
600 ppd
->colorspace
= PPD_CS_GRAY
;
601 ppd
->landscape
= -90;
604 * Read lines from the PPD file and add them to the file record...
612 while ((mask
= ppd_read(fp
, keyword
, name
, text
, &string
)) != 0)
615 printf("mask = %x, keyword = \"%s\"", mask
, keyword
);
618 printf(", name = \"%s\"", name
);
621 printf(", text = \"%s\"", text
);
625 if (strlen(string
) > 40)
626 printf(", string = %p", string
);
628 printf(", string = \"%s\"", string
);
634 if (strcmp(keyword
, "CloseUI") != 0 &&
635 strcmp(keyword
, "JCLCloseUI") != 0 &&
636 strcmp(keyword
, "CloseGroup") != 0 &&
637 strcmp(keyword
, "CloseSubGroup") != 0 &&
638 strncmp(keyword
, "Default", 7) != 0 &&
642 * Need a string value!
649 if (strcmp(keyword
, "LanguageLevel") == 0)
650 ppd
->language_level
= atoi(string
);
651 else if (strcmp(keyword
, "LanguageEncoding") == 0)
653 ppd
->lang_encoding
= string
;
654 string
= NULL
; /* Don't free this string below */
656 else if (strcmp(keyword
, "LanguageVersion") == 0)
658 ppd
->lang_version
= string
;
659 string
= NULL
; /* Don't free this string below */
661 else if (strcmp(keyword
, "Manufacturer") == 0)
663 ppd
->manufacturer
= string
;
664 string
= NULL
; /* Don't free this string below */
666 else if (strcmp(keyword
, "ModelName") == 0)
668 ppd
->modelname
= string
;
669 string
= NULL
; /* Don't free this string below */
671 else if (strcmp(keyword
, "PCFileName") == 0)
673 ppd
->pcfilename
= string
;
674 string
= NULL
; /* Don't free this string below */
676 else if (strcmp(keyword
, "NickName") == 0)
678 ppd
->nickname
= string
;
679 string
= NULL
; /* Don't free this string below */
681 else if (strcmp(keyword
, "Product") == 0)
683 ppd
->product
= string
;
684 string
= NULL
; /* Don't free this string below */
686 else if (strcmp(keyword
, "ShortNickName") == 0)
688 ppd
->shortnickname
= string
;
689 string
= NULL
; /* Don't free this string below */
691 else if (strcmp(keyword
, "TTRasterizer") == 0)
693 ppd
->ttrasterizer
= string
;
694 string
= NULL
; /* Don't free this string below */
696 else if (strcmp(keyword
, "JCLBegin") == 0)
698 ppd_decode(string
); /* Decode quoted string */
699 ppd
->jcl_begin
= string
;
700 string
= NULL
; /* Don't free this string below */
702 else if (strcmp(keyword
, "JCLEnd") == 0)
704 ppd_decode(string
); /* Decode quoted string */
705 ppd
->jcl_end
= string
;
706 string
= NULL
; /* Don't free this string below */
708 else if (strcmp(keyword
, "JCLToPSInterpreter") == 0)
710 ppd_decode(string
); /* Decode quoted string */
711 ppd
->jcl_ps
= string
;
712 string
= NULL
; /* Don't free this string below */
714 else if (strcmp(keyword
, "AccurateScreensSupport") == 0)
715 ppd
->accurate_screens
= strcmp(string
, "True") == 0;
716 else if (strcmp(keyword
, "ColorDevice") == 0)
717 ppd
->color_device
= strcmp(string
, "True") == 0;
718 else if (strcmp(keyword
, "ContoneOnly") == 0)
719 ppd
->contone_only
= strcmp(string
, "True") == 0;
720 else if (strcmp(keyword
, "DefaultColorSpace") == 0)
722 if (strcmp(string
, "CMY") == 0)
723 ppd
->colorspace
= PPD_CS_CMY
;
724 else if (strcmp(string
, "CMYK") == 0)
725 ppd
->colorspace
= PPD_CS_CMYK
;
726 else if (strcmp(string
, "RGB") == 0)
727 ppd
->colorspace
= PPD_CS_RGB
;
728 else if (strcmp(string
, "RGBK") == 0)
729 ppd
->colorspace
= PPD_CS_RGBK
;
730 else if (strcmp(string
, "N") == 0)
731 ppd
->colorspace
= PPD_CS_N
;
733 ppd
->colorspace
= PPD_CS_GRAY
;
735 else if (strcmp(keyword
, "cupsFlipDuplex") == 0)
736 ppd
->flip_duplex
= strcmp(string
, "True") == 0;
737 else if (strcmp(keyword
, "cupsManualCopies") == 0)
738 ppd
->manual_copies
= strcmp(string
, "True") == 0;
739 else if (strcmp(keyword
, "cupsModelNumber") == 0)
740 ppd
->model_number
= atoi(string
);
741 else if (strcmp(keyword
, "cupsColorProfile") == 0)
743 if (ppd
->num_profiles
== 0)
744 profile
= malloc(sizeof(ppd_profile_t
));
746 profile
= realloc(ppd
->profiles
, sizeof(ppd_profile_t
) *
747 (ppd
->num_profiles
+ 1));
749 ppd
->profiles
= profile
;
750 profile
+= ppd
->num_profiles
;
751 ppd
->num_profiles
++;
753 memset(profile
, 0, sizeof(ppd_profile_t
));
754 strlcpy(profile
->resolution
, name
, sizeof(profile
->resolution
));
755 strlcpy(profile
->media_type
, text
, sizeof(profile
->media_type
));
756 sscanf(string
, "%f%f%f%f%f%f%f%f%f%f%f", &(profile
->density
),
758 profile
->matrix
[0] + 0, profile
->matrix
[0] + 1,
759 profile
->matrix
[0] + 2, profile
->matrix
[1] + 0,
760 profile
->matrix
[1] + 1, profile
->matrix
[1] + 2,
761 profile
->matrix
[2] + 0, profile
->matrix
[2] + 1,
762 profile
->matrix
[2] + 2);
764 else if (strcmp(keyword
, "cupsFilter") == 0)
766 if (ppd
->num_filters
== 0)
767 filter
= malloc(sizeof(char *));
769 filter
= realloc(ppd
->filters
, sizeof(char *) * (ppd
->num_filters
+ 1));
778 ppd
->filters
= filter
;
779 filter
+= ppd
->num_filters
;
783 * Copy filter string and prevent it from being freed below...
789 else if (strcmp(keyword
, "Throughput") == 0)
790 ppd
->throughput
= atoi(string
);
791 else if (strcmp(keyword
, "Font") == 0)
794 * Add this font to the list of available fonts...
797 if (ppd
->num_fonts
== 0)
798 tempfonts
= (char **)malloc(sizeof(char *));
800 tempfonts
= (char **)realloc(ppd
->fonts
,
801 sizeof(char *) * (ppd
->num_fonts
+ 1));
803 if (tempfonts
== NULL
)
810 ppd
->fonts
= tempfonts
;
811 ppd
->fonts
[ppd
->num_fonts
] = strdup(name
);
814 else if (strcmp(keyword
, "VariablePaperSize") == 0 &&
815 strcmp(string
, "True") == 0 &&
816 !ppd
->variable_sizes
)
818 ppd
->variable_sizes
= 1;
821 * Add a "Custom" page size entry...
824 ppd_add_size(ppd
, "Custom");
827 * Add a "Custom" page size option...
830 if ((option
= ppdFindOption(ppd
, "PageSize")) == NULL
)
835 if ((temp
= ppd_get_group(ppd
, "General",
836 cupsLangString(language
,
837 CUPS_MSG_GENERAL
))) == NULL
)
844 if ((option
= ppd_get_option(temp
, "PageSize")) == NULL
)
852 if ((choice
= ppd_add_choice(option
, "Custom")) == NULL
)
859 strlcpy(choice
->text
, cupsLangString(language
, CUPS_MSG_VARIABLE
),
860 sizeof(choice
->text
));
863 else if (strcmp(keyword
, "MaxMediaWidth") == 0)
864 ppd
->custom_max
[0] = (float)atof(string
);
865 else if (strcmp(keyword
, "MaxMediaHeight") == 0)
866 ppd
->custom_max
[1] = (float)atof(string
);
867 else if (strcmp(keyword
, "ParamCustomPageSize") == 0)
869 if (strcmp(name
, "Width") == 0)
870 sscanf(string
, "%*s%*s%f%f", ppd
->custom_min
+ 0,
871 ppd
->custom_max
+ 0);
872 else if (strcmp(name
, "Height") == 0)
873 sscanf(string
, "%*s%*s%f%f", ppd
->custom_min
+ 1,
874 ppd
->custom_max
+ 1);
876 else if (strcmp(keyword
, "HWMargins") == 0)
877 sscanf(string
, "%f%f%f%f", ppd
->custom_margins
+ 0,
878 ppd
->custom_margins
+ 1, ppd
->custom_margins
+ 2,
879 ppd
->custom_margins
+ 3);
880 else if (strcmp(keyword
, "CustomPageSize") == 0 &&
881 strcmp(name
, "True") == 0)
883 if (!ppd
->variable_sizes
)
885 ppd
->variable_sizes
= 1;
888 * Add a "Custom" page size entry...
891 ppd_add_size(ppd
, "Custom");
894 * Add a "Custom" page size option...
897 if ((option
= ppdFindOption(ppd
, "PageSize")) == NULL
)
902 if ((temp
= ppd_get_group(ppd
, "General",
903 cupsLangString(language
,
904 CUPS_MSG_GENERAL
))) == NULL
)
906 DEBUG_puts("Unable to get general group!");
912 if ((option
= ppd_get_option(temp
, "PageSize")) == NULL
)
914 DEBUG_puts("Unable to get PageSize option!");
921 if ((choice
= ppd_add_choice(option
, "Custom")) == NULL
)
923 DEBUG_puts("Unable to add Custom choice!");
929 strlcpy(choice
->text
, cupsLangString(language
, CUPS_MSG_VARIABLE
),
930 sizeof(choice
->text
));
934 if ((option
= ppdFindOption(ppd
, "PageSize")) == NULL
)
936 DEBUG_puts("Unable to find PageSize option!");
942 if ((choice
= ppdFindChoice(option
, "Custom")) == NULL
)
944 DEBUG_puts("Unable to find Custom choice!");
950 choice
->code
= string
;
954 else if (strcmp(keyword
, "LandscapeOrientation") == 0)
956 if (strcmp(string
, "Minus90") == 0)
957 ppd
->landscape
= -90;
958 else if (strcmp(string
, "Plus90") == 0)
961 else if (strcmp(keyword
, "Emulators") == 0)
963 for (count
= 1, sptr
= string
; sptr
!= NULL
;)
964 if ((sptr
= strchr(sptr
, ' ')) != NULL
)
971 ppd
->num_emulations
= count
;
972 ppd
->emulations
= calloc(sizeof(ppd_emul_t
), count
);
974 for (i
= 0, sptr
= string
; i
< count
; i
++)
976 for (nameptr
= ppd
->emulations
[i
].name
;
977 *sptr
!= '\0' && *sptr
!= ' ';
979 if (nameptr
< (ppd
->emulations
[i
].name
+ sizeof(ppd
->emulations
[i
].name
) - 1))
988 else if (strncmp(keyword
, "StartEmulator_", 14) == 0)
992 for (i
= 0; i
< ppd
->num_emulations
; i
++)
993 if (strcmp(keyword
+ 14, ppd
->emulations
[i
].name
) == 0)
995 ppd
->emulations
[i
].start
= string
;
999 else if (strncmp(keyword
, "StopEmulator_", 13) == 0)
1003 for (i
= 0; i
< ppd
->num_emulations
; i
++)
1004 if (strcmp(keyword
+ 13, ppd
->emulations
[i
].name
) == 0)
1006 ppd
->emulations
[i
].stop
= string
;
1010 else if (strcmp(keyword
, "JobPatchFile") == 0)
1012 if (ppd
->patches
== NULL
)
1014 ppd
->patches
= string
;
1019 temp
= realloc(ppd
->patches
, strlen(ppd
->patches
) +
1020 strlen(string
) + 1);
1028 ppd
->patches
= temp
;
1030 strcpy(ppd
->patches
+ strlen(ppd
->patches
), string
);
1033 else if (strcmp(keyword
, "OpenUI") == 0)
1036 * Add an option record to the current sub-group, group, or file...
1040 strcpy(name
, name
+ 1); /* Eliminate leading asterisk */
1042 for (i
= strlen(name
) - 1; i
> 0 && isspace(name
[i
]); i
--)
1043 name
[i
] = '\0'; /* Eliminate trailing spaces */
1045 DEBUG_printf(("OpenUI of %s in group %s...\n", name
,
1046 group
? group
->text
: "(null)"));
1048 if (subgroup
!= NULL
)
1049 option
= ppd_get_option(subgroup
, name
);
1050 else if (group
== NULL
)
1052 if (strcmp(name
, "Collate") != 0 &&
1053 strcmp(name
, "Duplex") != 0 &&
1054 strcmp(name
, "InputSlot") != 0 &&
1055 strcmp(name
, "ManualFeed") != 0 &&
1056 strcmp(name
, "MediaType") != 0 &&
1057 strcmp(name
, "MediaColor") != 0 &&
1058 strcmp(name
, "MediaWeight") != 0 &&
1059 strcmp(name
, "OutputBin") != 0 &&
1060 strcmp(name
, "OutputMode") != 0 &&
1061 strcmp(name
, "OutputOrder") != 0 &&
1062 strcmp(name
, "PageSize") != 0 &&
1063 strcmp(name
, "PageRegion") != 0)
1064 group
= ppd_get_group(ppd
, "Extra",
1065 cupsLangString(language
, CUPS_MSG_EXTRA
));
1067 group
= ppd_get_group(ppd
, "General",
1068 cupsLangString(language
, CUPS_MSG_GENERAL
));
1077 DEBUG_printf(("Adding to group %s...\n", group
->text
));
1078 option
= ppd_get_option(group
, name
);
1082 option
= ppd_get_option(group
, name
);
1092 * Now fill in the initial information for the option...
1095 if (strcmp(string
, "PickMany") == 0)
1096 option
->ui
= PPD_UI_PICKMANY
;
1097 else if (strcmp(string
, "Boolean") == 0)
1098 option
->ui
= PPD_UI_BOOLEAN
;
1100 option
->ui
= PPD_UI_PICKONE
;
1104 strlcpy(option
->text
, text
, sizeof(option
->text
));
1105 ppd_fix(option
->text
);
1109 if (strcmp(name
, "PageSize") == 0)
1110 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_MEDIA_SIZE
),
1111 sizeof(option
->text
));
1112 else if (strcmp(name
, "MediaType") == 0)
1113 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_MEDIA_TYPE
),
1114 sizeof(option
->text
));
1115 else if (strcmp(name
, "InputSlot") == 0)
1116 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_MEDIA_SOURCE
),
1117 sizeof(option
->text
));
1118 else if (strcmp(name
, "ColorModel") == 0)
1119 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_OUTPUT_MODE
),
1120 sizeof(option
->text
));
1121 else if (strcmp(name
, "Resolution") == 0)
1122 strlcpy(option
->text
, cupsLangString(language
, CUPS_MSG_RESOLUTION
),
1123 sizeof(option
->text
));
1125 strlcpy(option
->text
, name
, sizeof(option
->text
));
1128 option
->section
= PPD_ORDER_ANY
;
1130 else if (strcmp(keyword
, "JCLOpenUI") == 0)
1133 * Find the JCL group, and add if needed...
1136 group
= ppd_get_group(ppd
, "JCL", "JCL");
1146 * Add an option record to the current JCLs...
1150 strcpy(name
, name
+ 1);
1152 option
= ppd_get_option(group
, name
);
1162 * Now fill in the initial information for the option...
1165 if (strcmp(string
, "PickMany") == 0)
1166 option
->ui
= PPD_UI_PICKMANY
;
1167 else if (strcmp(string
, "Boolean") == 0)
1168 option
->ui
= PPD_UI_BOOLEAN
;
1170 option
->ui
= PPD_UI_PICKONE
;
1172 strlcpy(option
->text
, text
, sizeof(option
->text
));
1174 option
->section
= PPD_ORDER_JCL
;
1177 else if (strcmp(keyword
, "CloseUI") == 0 ||
1178 strcmp(keyword
, "JCLCloseUI") == 0)
1180 else if (strcmp(keyword
, "OpenGroup") == 0)
1183 * Open a new group...
1194 * Separate the group name from the text (name/text)...
1197 if ((sptr
= strchr(string
, '/')) != NULL
)
1203 * Fix up the text...
1210 * Find/add the group...
1213 group
= ppd_get_group(ppd
, string
, sptr
);
1215 else if (strcmp(keyword
, "CloseGroup") == 0)
1217 else if (strcmp(keyword
, "OrderDependency") == 0 ||
1218 strcmp(keyword
, "NonUIOrderDependency") == 0)
1220 if (sscanf(string
, "%f%40s%40s", &order
, name
, keyword
) != 3)
1227 if (keyword
[0] == '*')
1228 strcpy(keyword
, keyword
+ 1);
1230 if (strcmp(name
, "ExitServer") == 0)
1231 section
= PPD_ORDER_EXIT
;
1232 else if (strcmp(name
, "Prolog") == 0)
1233 section
= PPD_ORDER_PROLOG
;
1234 else if (strcmp(name
, "DocumentSetup") == 0)
1235 section
= PPD_ORDER_DOCUMENT
;
1236 else if (strcmp(name
, "PageSetup") == 0)
1237 section
= PPD_ORDER_PAGE
;
1238 else if (strcmp(name
, "JCLSetup") == 0)
1239 section
= PPD_ORDER_JCL
;
1241 section
= PPD_ORDER_ANY
;
1249 * Only valid for Non-UI options...
1252 for (i
= ppd
->num_groups
, temp
= ppd
->groups
; i
> 0; i
--, temp
++)
1253 if (temp
->text
[0] == '\0')
1257 for (i
= 0; i
< temp
->num_options
; i
++)
1258 if (strcmp(keyword
, temp
->options
[i
].keyword
) == 0)
1260 temp
->options
[i
].section
= section
;
1261 temp
->options
[i
].order
= order
;
1267 option
->section
= section
;
1268 option
->order
= order
;
1271 else if (strncmp(keyword
, "Default", 7) == 0)
1276 if (strchr(string
, '/') != NULL
)
1277 *strchr(string
, '/') = '\0';
1285 * Only valid for Non-UI options...
1288 for (i
= ppd
->num_groups
, temp
= ppd
->groups
; i
> 0; i
--, temp
++)
1289 if (temp
->text
[0] == '\0')
1293 for (i
= 0; i
< temp
->num_options
; i
++)
1294 if (strcmp(keyword
, temp
->options
[i
].keyword
) == 0)
1296 strlcpy(temp
->options
[i
].defchoice
, string
,
1297 sizeof(temp
->options
[i
].defchoice
));
1302 strlcpy(option
->defchoice
, string
, sizeof(option
->defchoice
));
1304 else if (strcmp(keyword
, "UIConstraints") == 0 ||
1305 strcmp(keyword
, "NonUIConstraints") == 0)
1307 if (ppd
->num_consts
== 0)
1308 constraint
= calloc(sizeof(ppd_const_t
), 1);
1310 constraint
= realloc(ppd
->consts
,
1311 (ppd
->num_consts
+ 1) * sizeof(ppd_const_t
));
1313 if (constraint
== NULL
)
1320 ppd
->consts
= constraint
;
1321 constraint
+= ppd
->num_consts
;
1324 switch (sscanf(string
, "%40s%40s%40s%40s", constraint
->option1
,
1325 constraint
->choice1
, constraint
->option2
,
1326 constraint
->choice2
))
1328 case 0 : /* Error */
1329 case 1 : /* Error */
1334 case 2 : /* Two options... */
1336 * The following strcpy's are safe, as optionN and
1337 * choiceN are all the same size (size defined by PPD spec...)
1340 if (constraint
->option1
[0] == '*')
1341 strcpy(constraint
->option1
, constraint
->option1
+ 1);
1343 if (constraint
->choice1
[0] == '*')
1344 strcpy(constraint
->option2
, constraint
->choice1
+ 1);
1346 strcpy(constraint
->option2
, constraint
->choice1
);
1348 constraint
->choice1
[0] = '\0';
1349 constraint
->choice2
[0] = '\0';
1352 case 3 : /* Two options, one choice... */
1354 * The following strcpy's are safe, as optionN and
1355 * choiceN are all the same size (size defined by PPD spec...)
1358 if (constraint
->option1
[0] == '*')
1359 strcpy(constraint
->option1
, constraint
->option1
+ 1);
1361 if (constraint
->choice1
[0] == '*')
1363 strcpy(constraint
->choice2
, constraint
->option2
);
1364 strcpy(constraint
->option2
, constraint
->choice1
+ 1);
1365 constraint
->choice1
[0] = '\0';
1369 if (constraint
->option2
[0] == '*')
1370 strcpy(constraint
->option2
, constraint
->option2
+ 1);
1372 constraint
->choice2
[0] = '\0';
1376 case 4 : /* Two options, two choices... */
1377 if (constraint
->option1
[0] == '*')
1378 strcpy(constraint
->option1
, constraint
->option1
+ 1);
1380 if (constraint
->option2
[0] == '*')
1381 strcpy(constraint
->option2
, constraint
->option2
+ 1);
1385 else if (strcmp(keyword
, "PaperDimension") == 0)
1387 if ((size
= ppdPageSize(ppd
, name
)) == NULL
)
1388 size
= ppd_add_size(ppd
, name
);
1393 * Unable to add or find size!
1401 sscanf(string
, "%f%f", &(size
->width
), &(size
->length
));
1403 else if (strcmp(keyword
, "ImageableArea") == 0)
1405 if ((size
= ppdPageSize(ppd
, name
)) == NULL
)
1406 size
= ppd_add_size(ppd
, name
);
1411 * Unable to add or find size!
1419 sscanf(string
, "%f%f%f%f", &(size
->left
), &(size
->bottom
),
1420 &(size
->right
), &(size
->top
));
1422 else if (option
!= NULL
&&
1423 (mask
& (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
)) ==
1424 (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
))
1426 DEBUG_printf(("group = %p, subgroup = %p\n", group
, subgroup
));
1428 if (strcmp(keyword
, "PageSize") == 0)
1431 * Add a page size...
1434 if (ppdPageSize(ppd
, name
) == NULL
)
1435 ppd_add_size(ppd
, name
);
1439 * Add the option choice...
1442 choice
= ppd_add_choice(option
, name
);
1444 if (mask
& PPD_TEXT
)
1446 strlcpy(choice
->text
, text
, sizeof(choice
->text
));
1447 ppd_fix(choice
->text
);
1449 else if (strcmp(name
, "True") == 0)
1450 strcpy(choice
->text
, "Yes");
1451 else if (strcmp(name
, "False") == 0)
1452 strcpy(choice
->text
, "No");
1454 strlcpy(choice
->text
, name
, sizeof(choice
->text
));
1456 if (option
->section
== PPD_ORDER_JCL
)
1457 ppd_decode(string
); /* Decode quoted string */
1459 choice
->code
= string
;
1460 string
= NULL
; /* Don't free this string below */
1462 else if (strcmp(keyword
, "OpenSubGroup") != 0 &&
1463 strcmp(keyword
, "CloseSubGroup") != 0)
1465 char spec
[PPD_MAX_NAME
+ PPD_MAX_TEXT
];
1467 snprintf(spec
, sizeof(spec
), "%s/%s", name
, text
);
1468 ppd_add_attr(ppd
, keyword
, spec
, string
);
1470 string
= NULL
; /* Don't free this string below */
1478 printf("Premature EOF at %lu...\n", (unsigned long)ftell(fp
));
1482 * Set the option back-pointer for each choice...
1485 qsort(ppd
->groups
, ppd
->num_groups
, sizeof(ppd_group_t
),
1486 (int (*)(const void *, const void *))compare_groups
);
1488 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
1492 qsort(group
->options
, group
->num_options
, sizeof(ppd_option_t
),
1493 (int (*)(const void *, const void *))compare_options
);
1495 for (j
= group
->num_options
, option
= group
->options
;
1499 qsort(option
->choices
, option
->num_choices
, sizeof(ppd_choice_t
),
1500 (int (*)(const void *, const void *))compare_choices
);
1502 for (k
= 0; k
< option
->num_choices
; k
++)
1503 option
->choices
[k
].option
= (void *)option
;
1506 qsort(group
->subgroups
, group
->num_subgroups
, sizeof(ppd_group_t
),
1507 (int (*)(const void *, const void *))compare_groups
);
1509 for (j
= group
->num_subgroups
, subgroup
= group
->subgroups
;
1513 qsort(subgroup
->options
, subgroup
->num_options
, sizeof(ppd_option_t
),
1514 (int (*)(const void *, const void *))compare_options
);
1516 for (k
= group
->num_options
, option
= group
->options
;
1520 qsort(option
->choices
, option
->num_choices
, sizeof(ppd_choice_t
),
1521 (int (*)(const void *, const void *))compare_choices
);
1523 for (m
= 0; m
< option
->num_choices
; m
++)
1524 option
->choices
[m
].option
= (void *)option
;
1530 * Sort the attributes...
1533 if (ppd
->num_attrs
> 1)
1534 qsort(ppd
->attrs
, ppd
->num_attrs
, sizeof(ppd_attr_t
*),
1535 (int (*)(const void *, const void *))_ppd_attr_compare
);
1542 * 'ppdOpenFd()' - Read a PPD file into memory.
1545 ppd_file_t
* /* O - PPD file record */
1546 ppdOpenFd(int fd
) /* I - File to read from */
1548 FILE *fp
; /* File pointer */
1549 ppd_file_t
*ppd
; /* PPD file record */
1553 * Range check input...
1560 * Try to open the file and parse it...
1563 if ((fp
= fdopen(fd
, "r")) != NULL
)
1579 * 'ppdOpenFile()' - Read a PPD file into memory.
1582 ppd_file_t
* /* O - PPD file record */
1583 ppdOpenFile(const char *filename
) /* I - File to read from */
1585 FILE *fp
; /* File pointer */
1586 ppd_file_t
*ppd
; /* PPD file record */
1590 * Range check input...
1593 if (filename
== NULL
)
1597 * Try to open the file and parse it...
1600 if ((fp
= fopen(filename
, "r")) != NULL
)
1614 * 'compare_strings()' - Compare two strings.
1617 static int /* O - Result of comparison */
1618 compare_strings(char *s
, /* I - First string */
1619 char *t
) /* I - Second string */
1621 int diff
, /* Difference between digits */
1622 digits
; /* Number of digits */
1626 * Loop through both strings, returning only when a difference is
1627 * seen. Also, compare whole numbers rather than just characters, too!
1632 if (isdigit(*s
) && isdigit(*t
))
1635 * Got a number; start by skipping leading 0's...
1644 * Skip equal digits...
1647 while (isdigit(*s
) && *s
== *t
)
1654 * Bounce out if *s and *t aren't both digits...
1657 if (isdigit(*s
) && !isdigit(*t
))
1659 else if (!isdigit(*s
) && isdigit(*t
))
1661 else if (!isdigit(*s
) || !isdigit(*t
))
1670 * Figure out how many more digits there are...
1688 * Return if the number or value of the digits is different...
1693 else if (digits
> 0)
1698 else if (tolower(*s
) < tolower(*t
))
1700 else if (tolower(*s
) > tolower(*t
))
1710 * Return the results of the final comparison...
1723 * 'compare_groups()' - Compare two groups.
1726 static int /* O - Result of comparison */
1727 compare_groups(ppd_group_t
*g0
, /* I - First group */
1728 ppd_group_t
*g1
) /* I - Second group */
1730 return (compare_strings(g0
->text
, g1
->text
));
1735 * 'compare_options()' - Compare two options.
1738 static int /* O - Result of comparison */
1739 compare_options(ppd_option_t
*o0
,/* I - First option */
1740 ppd_option_t
*o1
)/* I - Second option */
1742 return (compare_strings(o0
->text
, o1
->text
));
1747 * 'compare_choices()' - Compare two choices.
1750 static int /* O - Result of comparison */
1751 compare_choices(ppd_choice_t
*c0
,/* I - First choice */
1752 ppd_choice_t
*c1
)/* I - Second choice */
1754 return (compare_strings(c0
->text
, c1
->text
));
1759 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
1763 static int /* O - Bitmask of fields read */
1764 ppd_read(FILE *fp
, /* I - File to read from */
1765 char *keyword
, /* O - Keyword from line */
1766 char *option
, /* O - Option from line */
1767 char *text
, /* O - Human-readable text from line */
1768 char **string
) /* O - Code/string data */
1770 int ch
, /* Character from file */
1771 colon
, /* Colon seen? */
1772 endquote
, /* Waiting for an end quote */
1773 mask
; /* Mask to be returned */
1774 char *keyptr
, /* Keyword pointer */
1775 *optptr
, /* Option pointer */
1776 *textptr
, /* Text pointer */
1777 *strptr
, /* Pointer into string */
1778 *lineptr
, /* Current position in line buffer */
1779 line
[65536]; /* Line buffer (64k) */
1783 * Range check everything...
1786 if (fp
== NULL
|| keyword
== NULL
|| option
== NULL
|| text
== NULL
||
1791 * Now loop until we have a valid line...
1806 while ((ch
= getc(fp
)) != EOF
&&
1807 (lineptr
- line
) < (sizeof(line
) - 1))
1809 if (ch
== '\r' || ch
== '\n')
1812 * Line feed or carriage return...
1815 if (lineptr
== line
) /* Skip blank lines */
1821 * Check for a trailing line feed...
1824 if ((ch
= getc(fp
)) == EOF
)
1832 if (!endquote
) /* Continue for multi-line text */
1840 * Any other character...
1845 if (ch
== ':' && strncmp(line
, "*%", 2) != 0)
1848 if (ch
== '\"' && colon
)
1850 endquote
= !endquote
;
1855 * End of quoted string; ignore trailing characters...
1858 while ((ch
= getc(fp
)) != EOF
)
1861 else if (ch
== '\r')
1880 * Didn't finish this quoted string...
1883 while ((ch
= getc(fp
)) != EOF
)
1891 * Didn't finish this line...
1894 while ((ch
= getc(fp
)) != EOF
)
1895 if (ch
== '\r' || ch
== '\n')
1898 * Line feed or carriage return...
1904 * Check for a trailing line feed...
1907 if ((ch
= getc(fp
)) == EOF
)
1917 if (lineptr
> line
&& lineptr
[-1] == '\n')
1922 /* DEBUG_printf(("LINE = \"%s\"\n", line));*/
1924 if (ch
== EOF
&& lineptr
== line
)
1939 if (line
[0] != '*') /* All lines start with an asterisk */
1942 if (strcmp(line
, "*") == 0 || /* (Bad) comment line */
1943 strncmp(line
, "*%", 2) == 0 || /* Comment line */
1944 strncmp(line
, "*?", 2) == 0 || /* Query line */
1945 strcmp(line
, "*End") == 0) /* End of multi-line string */
1954 while (*lineptr
!= '\0' && *lineptr
!= ':' && !isspace(*lineptr
))
1955 if ((keyptr
- keyword
) < (PPD_MAX_NAME
- 1))
1956 *keyptr
++ = *lineptr
++;
1960 if (strcmp(keyword
, "End") == 0)
1963 mask
|= PPD_KEYWORD
;
1965 /* DEBUG_printf(("keyword = \"%s\", lineptr = \"%s\"\n", keyword, lineptr));*/
1967 if (isspace(*lineptr
))
1970 * Get an option name...
1973 while (isspace(*lineptr
))
1978 while (*lineptr
!= '\0' && *lineptr
!= '\n' && *lineptr
!= ':' &&
1980 if ((optptr
- option
) < (PPD_MAX_NAME
- 1))
1981 *optptr
++ = *lineptr
++;
1986 /* DEBUG_printf(("option = \"%s\", lineptr = \"%s\"\n", option, lineptr));*/
1988 if (*lineptr
== '/')
1991 * Get human-readable text...
1998 while (*lineptr
!= '\0' && *lineptr
!= '\n' && *lineptr
!= ':')
1999 if ((textptr
- text
) < (PPD_MAX_LINE
- 1))
2000 *textptr
++ = *lineptr
++;
2008 /* DEBUG_printf(("text = \"%s\", lineptr = \"%s\"\n", text, lineptr));*/
2011 if (*lineptr
== ':')
2017 *string
= malloc(strlen(lineptr
) + 1);
2019 while (*lineptr
== ':' || isspace(*lineptr
))
2024 while (*lineptr
!= '\0')
2026 if (*lineptr
!= '\"')
2027 *strptr
++ = *lineptr
++;
2034 /* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
2046 * 'ppd_decode()' - Decode a string value...
2050 ppd_decode(char *string
) /* I - String to decode */
2052 char *inptr
, /* Input pointer */
2053 *outptr
; /* Output pointer */
2059 while (*inptr
!= '\0')
2060 if (*inptr
== '<' && isxdigit(inptr
[1]))
2063 * Convert hex to 8-bit values...
2067 while (isxdigit(*inptr
))
2069 if (isalpha(*inptr
))
2070 *outptr
= (tolower(*inptr
) - 'a' + 10) << 4;
2072 *outptr
= (*inptr
- '0') << 4;
2076 if (isalpha(*inptr
))
2077 *outptr
|= tolower(*inptr
) - 'a' + 10;
2079 *outptr
|= *inptr
- '0';
2085 while (*inptr
!= '>' && *inptr
!= '\0')
2087 while (*inptr
== '>')
2091 *outptr
++ = *inptr
++;
2098 * 'ppd_fix()' - Fix WinANSI characters in the range 0x80 to 0x9f to be
2099 * valid ISO-8859-1 characters...
2103 ppd_fix(char *string
) /* IO - String to fix */
2105 unsigned char *p
; /* Pointer into string */
2106 static unsigned char lut
[32] =/* Lookup table for characters */
2130 0x20, /* circumflex */
2132 0x20, /* double dot */
2137 '\"', /* should be right quotes */
2143 for (p
= (unsigned char *)string
; *p
; p
++)
2144 if (*p
>= 0x80 && *p
< 0xa0)
2145 *p
= lut
[*p
- 0x80];
2150 * End of "$Id: ppd.c,v 1.51.2.15 2002/05/16 13:59:59 mike Exp $".