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 continue;
61 }
63 if ($fsection){
64 if (preg_match("/^\*CloseGroup:*\s+\**$section\/*/", $line)){
65 $fsection= false;
66 fwrite ($wp, $line);
67 continue;
68 }
70 if (preg_match("/^\*OpenUI:*\s+\**$attribute\/*/", $line)){
71 $fattribute= true;
72 fwrite ($wp, $line);
73 continue;
74 }
76 if ($fattribute){
77 if (preg_match("/^\*CloseUI:*\s+\**$attribute\/*/", $line)){
78 $fattribute= false;
79 fwrite ($wp, $line);
80 continue;
81 }
83 if (preg_match("/^\*Default$attribute:*\s+/", $line)){
84 $line= "*Default$attribute: $value\n";
85 }
86 }
87 }
88 fwrite ($wp, $line);
89 }
91 fclose($wp);
92 fclose($rp);
94 copy("$file.tmp", "$file");
95 unlink("$file.tmp");
96 }
99 function saveProperties($ppdFile, $properties)
100 {
101 foreach ($properties as $name => $section){
102 foreach ($section as $attribute => $value){
103 if (is_array($value)){
104 $this->updateAttribute($ppdFile, $name, $attribute, $value['_default']);
105 }
106 }
107 }
108 }
111 function loadProperties($ppdFile)
112 {
113 $group= "";
114 $option= "";
115 $properties= array();
117 $fh= fopen ($ppdFile, 'r');
118 while (!feof($fh)) {
120 /* Read line */
121 $line= fgets($fh, 256);
122 if (strlen($line) >= 256){
123 trigger_error(_('Parsing PPD file %s failed - line too long. Trailing characters have been ignored'), E_USER_WARNING);
124 }
126 /* Trigger for option groups */
127 if (preg_match('/^\*OpenGroup:/i', $line)){
129 /* Sanity checks */
130 if ($group != ""){
131 trigger_error(_('Nested groups are not supported!'), E_USER_WARNING);
132 continue;
133 }
134 if (in_array($group, $properties)){
135 trigger_error(_('Group name not unique!'), E_USER_WARNING);
136 continue;
137 }
139 // TODO: Symbol values are not supported yet!
140 if (preg_match('/\^/', $line)){
141 trigger_error(_('Symbol values are not supported yet!'), E_USER_WARNING);
142 }
143 $complete= preg_replace('@^\*OpenGroup:\s+(.*)$@i', '\1', $line);
144 $complete= trim($complete, '"');
145 if (preg_match('@/@', $complete)){
146 $group= trim(preg_replace('@^\*OpenGroup:\s+"?([^/]+)/.*$@i', '\1', $line));
147 $name = preg_replace('@^\*OpenGroup:\s+"?[^/]+/([^/]+).*$@i', '\1', $line);
148 } else {
149 $group= $complete;
150 $name = $complete;
151 }
152 $properties[$group]= array('_name' => $name);
153 continue;
154 }
155 if (preg_match("/^\*CloseGroup:\s+\"?$group\"?/i", $line)){
156 $group= "";
157 continue;
158 }
160 /* Trigger for options */
161 if (preg_match('/^\*OpenUI\s+/i', $line)){
163 /* Sanity check */
164 if ($option != ""){
165 trigger_error(_('Nested options are not supported!'), E_USER_WARNING);
166 continue;
167 }
169 // TODO: Symbol values are not supported yet!
170 if (preg_match('/\^/', $line)){
171 trigger_error(_('Symbol values are not supported yet!'), E_USER_WARNING);
172 }
173 $complete= preg_replace('@^\*OpenUI\s+(.*)$@i', '\1', $line);
174 $complete= trim($complete, '"');
175 if (preg_match('@/@', $complete)){
176 $option= trim(preg_replace('@^\*OpenUI\s+([^/]+)/.*$@i', '\1', $line));
177 $name = trim(preg_replace('@^\*OpenUI\s+[^/]+/([^/]+).*$@i', '\1', $line));
178 } else {
179 $option= trim($complete);
180 $name = trim($complete);
181 }
183 /* Extract option type */
184 $type= trim(preg_replace('/^[^:]+:\s+/', '', $line));
185 $name= preg_replace('/:.*$/', '', $name);
186 $option= preg_replace('/:.*$/', '', $option);
188 // TODO: PickMany is not supported yet!
189 if (preg_match('/PickMany/i', $type)){
190 trigger_error(_('PickMany is not supported yet!'), E_USER_WARNING);
191 }
193 $properties[$group][$option]= array('_name' => $name, '_type' => $type);
194 continue;
195 }
196 /* Show interest for option parsing */
197 if ($option != ""){
199 $eoption= preg_replace('@\*@', '', $option);
201 /* Close section? */
202 if (preg_match("@^\*CloseUI:\s+\*$eoption@i", $line)){
203 $option= "";
204 continue;
205 }
207 /* Default value? */
208 if (preg_match("@^\*Default$eoption:@", $line)){
209 $c= preg_replace("@^\*Default$eoption:\s+@", "", $line);
210 $properties[$group][$option]['_default']= trim(trim($c, '"'));
211 continue;
212 }
214 /* Possible value? */
215 if (preg_match("@^\*$eoption\s+@", $line)){
216 #*PageSize Letter/US Letter: "<>setpagedevice"
217 $c= preg_replace("@^\*$eoption\s+([^/]+).*$@", "$1", $line);
218 $d= preg_replace("@^\*$eoption\s+[^/]+/([^:]+).*$@", "$1", $line);
219 $properties[$group][$option][trim($c)]= trim($d);
220 continue;
221 }
222 }
224 }
225 fclose ($fh);
227 return ($properties);
228 }
230 function loadDescription($ppdFile)
231 {
232 $model= "";
233 $manufacturer= "";
235 $fh= fopen ($ppdFile, 'r');
236 while (!feof($fh)) {
238 /* Read line */
239 $line= fgets($fh, 256);
240 if (strlen($line) >= 256){
241 trigger_error(_('Parsing PPD file %s failed - line too long. Trailing characters have been ignored'), E_USER_WARNING);
242 }
244 /* Extract interesting informations */
245 if (preg_match('/^\*Manufacturer:/i', $line)){
246 $manufacturer= preg_replace('/^\*Manufacturer:\s+"?([^"]+)"?.*$/i', '\1', $line);
247 }
248 if (preg_match('/^\*ModelName:/i', $line)){
249 $model= preg_replace('/^\*ModelName:\s+"?([^"]+)"?.*$/i', '\1', $line);
250 }
252 /* Got everything we need? Skip rest for speed reasons... */
253 if ($model != '' && $manufacturer != ''){
254 break;
255 }
256 }
257 fclose ($fh);
259 /* Write out a notice that the PPD file seems to be broken if we can't
260 extract any usefull informations */
261 if ($model == '' || $manufacturer == ''){
262 trigger_error(sprintf(_('Parsing PPD file %s failed - no information found.'), $ppdFile), E_USER_WARNING);
263 }
265 return ($manufacturer.' - '.$model);
266 }
269 function getPrinterList($reload= false)
270 {
271 /* Load list of PPD files */
272 if (count($this->cachedList) == 0 || $reload){
273 $list= $this->findPPD($this->path);
275 /* Load descriptive informations to build final printer list */
276 $this->cachedList= array();
277 foreach ($list as $ppdFile){
278 $this->cachedList[$ppdFile]= $this->loadDescription($ppdFile);
279 }
281 }
283 return ($this->cachedList);
284 }
286 }
288 ?>