1 <?php
3 class ppdManager
4 {
5 var $path= "";
6 var $cachedList= array();
8 function ppdManager($path)
9 {
10 $this->path= $path;
11 }
14 function findPPD($path)
15 {
16 $list= array();
17 $currentDir= getcwd();
19 $dh = opendir($path);
20 while(false !== ($file = readdir($dh))){
22 /* Skip well known files */
23 if( $file == '.' || $file == '..'){
24 continue;
25 }
27 /* Recurse through all "common" directories */
28 if(is_dir($path.'/'.$file)){
29 $list= array_merge($list, $this->findPPD($path.'/'.$file));
30 continue;
31 }
33 /* Check for PPD extension */
34 if (preg_match('/\.ppd$/i', $file)){
35 $list[]= $path.'/'.$file;
36 }
37 }
39 closedir($dh);
40 chdir ($currentDir);
41 return ($list);
42 }
45 function updateAttribute($file, $section, $attribute, $value)
46 {
47 $fsection= false;
48 $fattribute= false;
49 $section= preg_replace('/^\*/', '', $section);
50 $attribute= preg_replace('/^\*/', '', $attribute);
52 $rp= fopen($file, "r");
53 $wp= fopen("$file.tmp", "w");
55 while (!feof($rp)){
56 $line= fgets($rp, 1024);
58 if (preg_match("/\*OpenGroup:*\s+\**$section\/*/", $line)){
59 $fsection= true;
60 fwrite ($wp, $line);
61 continue;
62 }
64 if ($fsection){
65 if (preg_match("/^\*CloseGroup:*\s+\**$section\/*/", $line)){
66 $fsection= false;
67 fwrite ($wp, $line);
68 continue;
69 }
71 if (preg_match("/^\*OpenUI:*\s+\**$attribute\/*/", $line)){
72 $fattribute= true;
73 fwrite ($wp, $line);
74 continue;
75 }
77 if ($fattribute){
78 if (preg_match("/^\*CloseUI:*\s+\**$attribute\/*/", $line)){
79 $fattribute= false;
80 fwrite ($wp, $line);
81 continue;
82 }
84 if (preg_match("/^\*Default$attribute:*\s+/", $line)){
85 $line= "*Default$attribute: $value\n";
86 }
87 }
88 }
89 fwrite ($wp, $line);
90 }
92 fclose($wp);
93 fclose($rp);
95 copy("$file.tmp", "$file");
96 unlink("$file.tmp");
97 }
100 function saveProperties($ppdFile, $properties)
101 {
102 foreach ($properties as $name => $section){
103 foreach ($section as $attribute => $value){
104 if (is_array($value)){
105 $this->updateAttribute($ppdFile, $name, $attribute, $value['_default']);
106 }
107 }
108 }
109 }
112 function loadProperties($ppdFile)
113 {
114 $group= "";
115 $option= "";
116 $properties= array();
118 $fh= fopen ($ppdFile, 'r');
119 while (!feof($fh)) {
121 /* Read line */
122 $line= fgets($fh, 256);
123 if (strlen($line) >= 256){
124 trigger_error(_('Parsing PPD file %s failed - line too long. Trailing characters have been ignored'), E_USER_WARNING);
125 }
127 /* Trigger for option groups */
128 if (preg_match('/^\*OpenGroup:/i', $line)){
130 /* Sanity checks */
131 if ($group != ""){
132 trigger_error(_('Nested groups are not supported!'), E_USER_WARNING);
133 continue;
134 }
135 if (in_array($group, $properties)){
136 trigger_error(_('Group name not unique!'), E_USER_WARNING);
137 continue;
138 }
140 // TODO: Symbol values are not supported yet!
141 if (preg_match('/\^/', $line)){
142 trigger_error(_('Symbol values are not supported yet!'), E_USER_WARNING);
143 }
144 $complete= preg_replace('@^\*OpenGroup:\s+(.*)$@i', '\1', $line);
145 $complete= trim($complete, '"');
146 if (preg_match('@/@', $complete)){
147 $group= trim(preg_replace('@^\*OpenGroup:\s+"?([^/]+)/.*$@i', '\1', $line));
148 $name = preg_replace('@^\*OpenGroup:\s+"?[^/]+/([^/]+).*$@i', '\1', $line);
149 } else {
150 $group= $complete;
151 $name = $complete;
152 }
153 $properties[$group]= array('_name' => $name);
154 continue;
155 }
156 if (preg_match("/^\*CloseGroup:\s+\"?$group\"?/i", $line)){
157 $group= "";
158 continue;
159 }
161 /* Trigger for options */
162 if (preg_match('/^\*OpenUI\s+/i', $line)){
164 /* Sanity check */
165 if ($option != ""){
166 trigger_error(_('Nested options are not supported!'), E_USER_WARNING);
167 continue;
168 }
170 // TODO: Symbol values are not supported yet!
171 if (preg_match('/\^/', $line)){
172 trigger_error(_('Symbol values are not supported yet!'), E_USER_WARNING);
173 }
174 $complete= preg_replace('@^\*OpenUI\s+(.*)$@i', '\1', $line);
175 $complete= trim($complete, '"');
176 if (preg_match('@/@', $complete)){
177 $option= trim(preg_replace('@^\*OpenUI\s+([^/]+)/.*$@i', '\1', $line));
178 $name = trim(preg_replace('@^\*OpenUI\s+[^/]+/([^/]+).*$@i', '\1', $line));
179 } else {
180 $option= trim($complete);
181 $name = trim($complete);
182 }
184 /* Extract option type */
185 $type= trim(preg_replace('/^[^:]+:\s+/', '', $line));
186 $name= preg_replace('/:.*$/', '', $name);
187 $option= preg_replace('/:.*$/', '', $option);
189 // TODO: PickMany is not supported yet!
190 if (preg_match('/PickMany/i', $type)){
191 trigger_error(_('PickMany is not supported yet!'), E_USER_WARNING);
192 }
194 $properties[$group][$option]= array('_name' => $name, '_type' => $type);
195 continue;
196 }
197 /* Show interest for option parsing */
198 if ($option != ""){
200 $eoption= preg_replace('@\*@', '', $option);
202 /* Close section? */
203 if (preg_match("@^\*CloseUI:\s+\*$eoption@i", $line)){
204 $option= "";
205 continue;
206 }
208 /* Default value? */
209 if (preg_match("@^\*Default$eoption:@", $line)){
210 $c= preg_replace("@^\*Default$eoption:\s+@", "", $line);
211 $properties[$group][$option]['_default']= trim(trim($c, '"'));
212 continue;
213 }
215 /* Possible value? */
216 if (preg_match("@^\*$eoption\s+@", $line)){
217 #*PageSize Letter/US Letter: "<>setpagedevice"
218 $c= preg_replace("@^\*$eoption\s+([^/]+).*$@", "$1", $line);
219 $d= preg_replace("@^\*$eoption\s+[^/]+/([^:]+).*$@", "$1", $line);
220 $properties[$group][$option][trim($c)]= trim($d);
221 continue;
222 }
223 }
225 }
226 fclose ($fh);
228 return ($properties);
229 }
231 function loadDescription($ppdFile)
232 {
233 $model= "";
234 $manufacturer= "";
236 $fh= fopen ($ppdFile, 'r');
237 while (!feof($fh)) {
239 /* Read line */
240 $line= fgets($fh, 256);
241 if (strlen($line) >= 256){
242 trigger_error(_('Parsing PPD file %s failed - line too long. Trailing characters have been ignored'), E_USER_WARNING);
243 }
245 /* Extract interesting informations */
246 if (preg_match('/^\*Manufacturer:/i', $line)){
247 $manufacturer= preg_replace('/^\*Manufacturer:\s+"?([^"]+)"?.*$/i', '\1', $line);
248 }
249 if (preg_match('/^\*ModelName:/i', $line)){
250 $model= preg_replace('/^\*ModelName:\s+"?([^"]+)"?.*$/i', '\1', $line);
251 }
253 /* Got everything we need? Skip rest for speed reasons... */
254 if ($model != '' && $manufacturer != ''){
255 break;
256 }
257 }
258 fclose ($fh);
260 /* Write out a notice that the PPD file seems to be broken if we can't
261 extract any usefull informations */
262 if ($model == '' || $manufacturer == ''){
263 trigger_error(sprintf(_('Parsing PPD file %s failed - no information found.'), $ppdFile), E_USER_WARNING);
264 }
266 return ($manufacturer.' - '.$model);
267 }
270 function getPrinterList($reload= false)
271 {
272 /* Load list of PPD files */
273 if (count($this->cachedList) == 0 || $reload){
274 $list= $this->findPPD($this->path);
276 /* Load descriptive informations to build final printer list */
277 $this->cachedList= array();
278 foreach ($list as $ppdFile){
279 $this->cachedList[$ppdFile]= $this->loadDescription($ppdFile);
280 }
282 }
284 return ($this->cachedList);
285 }
287 }
289 ?>