1/*
2 * $Id: ppd.c,v 1.17 2009-10-14 02:24:05 didg Exp $
3 *
4 * Copyright (c) 1995 Regents of The University of Michigan.
5 * All Rights Reserved.  See COPYRIGHT.
6 */
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif /* HAVE_CONFIG_H */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <errno.h>
16#include <atalk/logger.h>
17#include <sys/types.h>
18#include <sys/param.h>
19#include <sys/time.h>
20#include <netatalk/at.h>
21#include <atalk/atp.h>
22
23#include "printer.h"
24#include "ppd.h"
25
26struct ppd_font		*ppd_fonts = NULL;
27
28struct ppd_feature	ppd_features[] = {
29    { "*LanguageLevel",	NULL },
30    { "*PSVersion",	NULL },
31#ifdef HAVE_CUPS
32    { "*FreeVM",	"33554432" },
33#else
34    { "*FreeVM",	NULL },
35#endif
36    { "*Product",	NULL },
37    { "*PCFileName",	NULL },
38    { "*ModelName",	NULL },
39    { "*NickName",	NULL },
40    { "*ColorDevice",	NULL },
41    { "*FaxSupport",	NULL },
42    { "*TTRasterizer",	NULL },
43    { NULL, NULL },
44};
45
46struct ppdent {
47    char	*pe_main;
48    char	*pe_option;
49    char	*pe_translation;
50    char	*pe_value;
51};
52
53#ifndef SHOWPPD
54static int ppd_inited;
55
56static void ppd_init(void)
57{
58    if (ppd_inited)
59        return;
60
61    ppd_inited++;
62
63    if (printer->p_ppdfile)
64        read_ppd( printer->p_ppdfile, 0 );
65}
66#endif /* SHOWPPD */
67
68
69/* quick and ugly hack to be able to read
70   ppd files with Mac line ending */
71static char* my_fgets(char *buf, size_t bufsize, FILE *stream)
72{
73    int p;           /* uninitialized, OK 310105 */
74    size_t count = 0;
75
76    while (count < (bufsize - 1) && EOF != (p=fgetc(stream))) {
77        buf[count] = p;
78        count++;
79        if ( p == '\r' || p == '\n')
80           break;
81    }
82
83    if (p == EOF && count == 0)
84        return NULL;
85
86    /* translate line endings */
87    if ( buf[count - 1] == '\r')
88        buf[count - 1] = '\n';
89
90    buf[count] = 0;
91    return buf;
92}
93
94static struct ppdent *getppdent( FILE *stream)
95{
96    static char			buf[ 1024 ];
97    static struct ppdent	ppdent;
98    char			*p, *q;
99
100    ppdent.pe_main = ppdent.pe_option = ppdent.pe_translation =
101	    ppdent.pe_value = NULL;
102
103    while (( p = my_fgets( buf, sizeof( buf ), stream )) != NULL ) {
104	if ( *p != '*' ) {	/* main key word */
105	    continue;
106	}
107	if ( p[ strlen( p ) - 1 ] != '\n') {
108	    LOG(log_error, logtype_papd, "getppdent: line too long" );
109	    continue;
110	}
111
112	q = p;
113	while ( (*p != ' ') && (*p != '\t') && (*p != ':') && (*p != '\n') ) {
114	    p++;
115	}
116	if ( (*( q + 1 ) == '%') || (*( q + 1 ) == '?') ) {	/* comments & queries */
117	    continue;
118	}
119	ppdent.pe_main = q;
120	if ( *p == '\n' ) {
121	    *p = '\0';
122	    ppdent.pe_option = ppdent.pe_translation = ppdent.pe_value = NULL;
123	    return( &ppdent );
124	}
125
126	if ( *p != ':' ) {	/* option key word */
127	    *p++ = '\0';
128
129	    while ( (*p == ' ') || (*p == '\t') ) {
130		p++;
131	    }
132
133	    q = p;
134	    while ( (*p != ':') && (*p != '/') && (*p != '\n') ) {
135		p++;
136	    }
137
138	    if ( *p == '\n' ) {
139		continue;
140	    }
141
142	    ppdent.pe_option = q;
143	    if ( *p == '/' ) {	/* translation string */
144		*p++ = '\0';
145		q = p;
146		while ( *p != ':' && *p != '\n' ) {
147		    p++;
148		}
149		if ( *p != ':' ) {
150		    continue;
151		}
152
153		ppdent.pe_translation = q;
154	    } else {
155		ppdent.pe_translation = NULL;
156	    }
157	}
158	*p++ = '\0';
159
160	while ( (*p == ' ') || (*p == '\t') ) {
161	    p++;
162	}
163
164	/* value */
165	q = p;
166	while ( *p != '\n' ) {
167	    p++;
168	}
169	*p = '\0';
170	ppdent.pe_value = q;
171
172	return( &ppdent );
173    }
174
175    return( NULL );
176}
177
178int read_ppd(char *file, int fcnt)
179{
180    FILE		*ppdfile;
181    struct ppdent	*pe;
182    struct ppd_feature	*pfe;
183    struct ppd_font	*pfo;
184
185    if ( fcnt > 20 ) {
186	LOG(log_error, logtype_papd, "read_ppd: %s: Too many files!", file );
187	return( -1 );
188    }
189
190    if (( ppdfile = fopen( file, "r" )) == NULL ) {
191	LOG(log_error, logtype_papd, "read_ppd %s: %s", file, strerror(errno) );
192	return( -1 );
193    }
194
195    while (( pe = getppdent( ppdfile )) != NULL ) {
196	/* *Include files */
197	if ( strcmp( pe->pe_main, "*Include" ) == 0 ) {
198	    read_ppd( pe->pe_value, fcnt + 1 );
199	    continue;
200	}
201
202	/* *Font */
203	if ( strcmp( pe->pe_main, "*Font" ) == 0 && pe->pe_option ) {
204	    for ( pfo = ppd_fonts; pfo; pfo = pfo->pd_next ) {
205		if ( strcmp( pfo->pd_font, pe->pe_option ) == 0 ) {
206		    break;
207		}
208	    }
209	    if ( pfo ) {
210		continue;
211	    }
212
213	    if (( pfo = (struct ppd_font *)malloc( sizeof( struct ppd_font )))
214		    == NULL ) {
215		LOG(log_error, logtype_papd, "malloc: %s", strerror(errno) );
216		exit( 1 );
217	    }
218	    if (( pfo->pd_font =
219		    (char *)malloc( strlen( pe->pe_option ) + 1 )) == NULL ) {
220		LOG(log_error, logtype_papd, "malloc: %s", strerror(errno) );
221		exit( 1 );
222	    }
223	    strcpy( pfo->pd_font, pe->pe_option );
224	    pfo->pd_next = ppd_fonts;
225	    ppd_fonts = pfo;
226	    continue;
227	}
228
229
230	/* Features */
231	for ( pfe = ppd_features; pfe->pd_name; pfe++ ) {
232	    if ( strcmp( pe->pe_main, pfe->pd_name ) == 0 ) {
233		break;
234	    }
235	}
236	if ( pfe->pd_name && pe->pe_value ) {
237	    if (( pfe->pd_value =
238		    (char *)malloc( strlen( pe->pe_value ) + 1 )) == NULL ) {
239		LOG(log_error, logtype_papd, "malloc: %s", strerror(errno) );
240		exit( 1 );
241	    }
242
243	    strcpy( pfe->pd_value, pe->pe_value );
244	    continue;
245	}
246    }
247
248    fclose( ppdfile );
249    return( 0 );
250}
251
252struct ppd_font *ppd_font( char *font)
253{
254    struct ppd_font	*pfo;
255
256#ifndef SHOWPPD
257    if ( ! ppd_inited ) {
258	ppd_init();
259    }
260#endif /* SHOWPPD */
261
262    for ( pfo = ppd_fonts; pfo; pfo = pfo->pd_next ) {
263	if ( strcmp( pfo->pd_font, font ) == 0 ) {
264	    return( pfo );
265	}
266    }
267    return( NULL );
268}
269
270struct ppd_feature *ppd_feature( const char *feature, int len)
271{
272    struct ppd_feature	*pfe;
273    char		ppd_feature_main[ 256 ];
274    const char		*end, *p;
275    char 		*q;
276
277#ifndef SHOWPPD
278    if ( ! ppd_inited ) {
279	ppd_init();
280    }
281#endif /* SHOWPPD */
282
283    if (len > sizeof(ppd_feature_main) -1)
284        return( NULL );
285
286    for ( end = feature + len, p = feature, q = ppd_feature_main;
287	    (p <= end) && (*p != '\n') && (*p != '\r'); p++, q++ ) {
288	*q = *p;
289    }
290    if ( p > end ) {
291	return( NULL );
292    }
293    *q = '\0';
294
295    for ( pfe = ppd_features; pfe->pd_name; pfe++ ) {
296	if ( (strcmp( pfe->pd_name, ppd_feature_main ) == 0) && pfe->pd_value ) {
297	    return( pfe );
298	}
299    }
300
301    return( NULL );
302}
303