1 <?php
3 class ppdManager
4 {
5 var $path= "";
6 var $cachedList= array();
8 function ppdManager($path)
9 {
10 if(is_dir($path)){
11 $this->path= $path;
12 }else{
13 print_red(sprintf(_("PPD manager : The specified path '%s' doesn't exists."),$path));
14 return (false);
15 }
16 }
19 function findPPD($path)
20 {
21 $list= array();
22 $currentDir= getcwd();
24 $dh = opendir($path);
25 while(false !== ($file = readdir($dh))){
27 /* Skip well known files */
28 if( $file == '.' || $file == '..'){
29 continue;
30 }
32 /* Recurse through all "common" directories */
33 if(is_dir($path.'/'.$file)){
34 $list= array_merge($list, $this->findPPD($path.'/'.$file));
35 continue;
36 }
38 /* Check for PPD extension */
39 if (preg_match('/\.ppd$/i', $file)){
40 $list[]= $path.'/'.$file;
41 }
42 }
44 closedir($dh);
45 chdir ($currentDir);
46 return ($list);
47 }
50 function updateAttribute($file, $section, $attribute, $value)
51 {
52 $fsection= false;
53 $fattribute= false;
54 $section= preg_replace('/^\*/', '', $section);
55 $attribute= preg_replace('/^\*/', '', $attribute);
57 $rp= fopen($file, "r");
58 $wp= fopen("$file.tmp", "w");
60 while (!feof($rp)){
61 $lines[]= fgets($rp, 1024);
62 }
64 $ret = "";
65 $done =false;
66 foreach($lines as $nr => $line){
68 if (preg_match("/\*OpenGroup:*\s+\**$section\/*/", $line)){
69 $fsection= true;
70 $ret .=$line;
71 continue;
72 }
74 if (($fsection) && ($section != "NO_SECTION")){
75 if (preg_match("/^\*CloseGroup:*\s+\**$section\/*/", $line)){
76 $fsection= false;
77 $ret .=$line;
78 continue;
79 }
82 if (preg_match("/^\*OpenUI:*\s+\**$attribute\/*/", $line)){
83 $fattribute= true;
84 $ret .= $line;
85 continue;
86 }
88 if ($fattribute){
89 if (preg_match("/^\*CloseUI:*\s+\**$attribute\/*/", $line)){
90 $fattribute= false;
91 $ret .= $line;
92 continue;
93 }
95 if (preg_match("/^\*Default$attribute:*\s+/", $line)){
96 $line= "*Default$attribute: $value\n";
97 $done =true;
98 }
99 }
100 }else{
101 if (preg_match("/^\*OpenUI:*\s+\**$attribute\/*/", $line)){
102 $fattribute= true;
103 $ret .= $line;
104 continue;
105 }
107 if ($fattribute){
108 if (preg_match("/^\*CloseUI:*\s+\**$attribute\/*/", $line)){
109 $fattribute= false;
110 $ret .= $line;
111 continue;
112 }
114 if (preg_match("/^\*Default$attribute:*\s+/", $line)){
115 $line= "*Default$attribute: $value\n";
116 $done =true;
117 }
118 }
119 }
120 $ret .=$line;
121 }
123 fwrite($wp,$ret);
125 fclose($wp);
126 fclose($rp);
128 copy("$file.tmp", "$file");
129 unlink("$file.tmp");
130 }
133 function saveProperties($ppdFile, $properties)
134 {
135 foreach ($properties as $name => $section){
136 foreach ($section as $attribute => $value){
137 if (is_array($value)){
138 $this->updateAttribute($ppdFile, $name, $attribute, $value['_default']);
139 }
140 }
141 }
142 }
144 function loadProperties($ppdFile)
145 {
146 $group= "";
147 $option= "";
148 $properties= array();
150 $fh= fopen ($ppdFile, 'r');
151 while (!feof($fh)) {
153 /* Read line */
154 $line= fgets($fh, 256);
155 if (strlen($line) >= 256){
156 trigger_error(_('Parsing PPD file %s failed - line too long. Trailing characters have been ignored'), E_USER_WARNING);
157 }
159 /* Trigger for option groups */
160 if (preg_match('/^\*OpenGroup:/i', $line)){
162 /* Sanity checks */
163 if ($group != ""){
164 trigger_error(_('Nested groups are not supported!'), E_USER_WARNING);
165 continue;
166 }
167 if (in_array($group, $properties)){
168 trigger_error(_('Group name not unique!'), E_USER_WARNING);
169 continue;
170 }
172 // TODO: Symbol values are not supported yet!
173 if (preg_match('/\^/', $line)){
174 trigger_error(_('Symbol values are not supported yet!'), E_USER_WARNING);
175 }
176 $complete= preg_replace('@^\*OpenGroup:\s+(.*)$@i', '\1', $line);
177 $complete= trim($complete, '"');
178 if (preg_match('@/@', $complete)){
179 $group= trim(preg_replace('@^\*OpenGroup:\s+"?([^/]+)/.*$@i', '\1', $line));
180 $name = preg_replace('@^\*OpenGroup:\s+"?[^/]+/([^/]+).*$@i', '\1', $line);
181 } else {
182 $group= $complete;
183 $name = $complete;
184 }
185 $properties[$group]= array('_name' => $name);
186 continue;
187 }
188 if (preg_match("/^\*CloseGroup:\s+\"?$group\"?/i", $line)){
189 $group= "";
190 continue;
191 }
193 /* Trigger for options */
194 if (preg_match('/^\*OpenUI\s+/i', $line)){
196 /* Sanity check */
197 if ($option != ""){
198 trigger_error(_('Nested options are not supported!'), E_USER_WARNING);
199 continue;
200 }
202 // TODO: Symbol values are not supported yet!
203 if (preg_match('/\^/', $line)){
204 trigger_error(_('Symbol values are not supported yet!'), E_USER_WARNING);
205 }
206 $complete= preg_replace('@^\*OpenUI\s+(.*)$@i', '\1', $line);
207 $complete= trim($complete, '"');
208 if (preg_match('@/@', $complete)){
209 $option= trim(preg_replace('@^\*OpenUI\s+([^/]+)/.*$@i', '\1', $line));
210 $name = trim(preg_replace('@^\*OpenUI\s+[^/]+/([^/]+).*$@i', '\1', $line));
211 } else {
212 $option= trim($complete);
213 $name = trim($complete);
214 }
216 /* Extract option type */
217 $type= trim(preg_replace('/^[^:]+:\s+/', '', $line));
218 $name= preg_replace('/:.*$/', '', $name);
219 $option= preg_replace('/:.*$/', '', $option);
221 // TODO: PickMany is not supported yet!
222 if (preg_match('/PickMany/i', $type)){
223 trigger_error(_('PickMany is not supported yet!'), E_USER_WARNING);
224 }
225 if(empty($group)){
226 $properties["NO_SECTION"][$option]= array('_name' => $name, '_type' => $type);
227 }else{
228 $properties[$group][$option]= array('_name' => $name, '_type' => $type);
229 }
230 continue;
231 }
232 /* Show interest for option parsing */
233 if ($option != ""){
235 $eoption= preg_replace('@\*@', '', $option);
237 /* Close section? */
238 if (preg_match("@^\*CloseUI:\s+\*$eoption@i", $line)){
239 $option= "";
240 continue;
241 }
243 /* Default value? */
244 if (preg_match("@^\*Default$eoption:@", $line)){
245 $c= preg_replace("@^\*Default$eoption:\s+@", "", $line);
246 if(empty($group)){
247 $properties["NO_SECTION"][$option]['_default']= trim(trim($c, '"'));
248 }else{
249 $properties[$group][$option]['_default']= trim(trim($c, '"'));
250 }
251 continue;
252 }
254 /* Possible value? */
255 if (preg_match("@^\*$eoption\s+@", $line)){
256 #*PageSize Letter/US Letter: "<>setpagedevice"
257 $c= preg_replace("@^\*$eoption\s+([^/]+).*$@", "$1", $line);
258 $d= preg_replace("@^\*$eoption\s+[^/]+/([^:]+).*$@", "$1", $line);
259 if(empty($group)){
260 $properties["NO_SECTION"][$option][trim($c)]= trim($d);
261 }else{
262 $properties[$group][$option][trim($c)]= trim($d);
263 }
264 continue;
265 }
266 }
267 }
268 fclose ($fh);
269 return ($properties);
270 }
272 function loadDescription($ppdFile)
273 {
274 $model= "";
275 $manufacturer= "";
277 $fh= fopen ($ppdFile, 'r');
278 while ((!feof($fh))&&($fh)) {
280 /* Read line */
281 $line= fgets($fh, 256);
282 if (strlen($line) >= 256){
283 trigger_error(_('Parsing PPD file %s failed - line too long. Trailing characters have been ignored'), E_USER_WARNING);
284 }
286 /* Extract interesting informations */
287 if (preg_match('/^\*Manufacturer:/i', $line)){
288 $manufacturer= preg_replace('/^\*Manufacturer:\s+"?([^"]+)"?.*$/i', '\1', $line);
289 }
290 if (preg_match('/^\*ModelName:/i', $line)){
291 $model= preg_replace('/^\*ModelName:\s+"?([^"]+)"?.*$/i', '\1', $line);
292 }
294 /* Got everything we need? Skip rest for speed reasons... */
295 if ($model != '' && $manufacturer != ''){
296 break;
297 }
298 }
299 fclose ($fh);
301 /* Write out a notice that the PPD file seems to be broken if we can't
302 extract any usefull informations */
303 if ($model == '' || $manufacturer == ''){
304 trigger_error(sprintf(_('Parsing PPD file %s failed - no information found.'), $ppdFile), E_USER_WARNING);
305 }
307 return ($manufacturer.' - '.$model);
308 }
311 function getPrinterList($reload= false)
312 {
313 /* Load list of PPD files */
314 if (count($this->cachedList) == 0 || $reload){
315 $list= $this->findPPD($this->path);
317 /* Load descriptive informations to build final printer list */
318 $this->cachedList= array();
319 foreach ($list as $ppdFile){
320 $this->cachedList[$ppdFile]= $this->loadDescription($ppdFile);
321 }
323 }
325 return ($this->cachedList);
326 }
328 }
330 ?>