1 /*
2 * cups - Python bindings for CUPS
3 * Copyright (C) 2002-2020 Tim Waugh <twaugh@redhat.com>
4 * Authors: Tim Waugh <twaugh@redhat.com>
5 * Zdenek Dohnal <zdohnal@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 #include "cupsppd.h"
23 #include "cupsmodule.h"
24
25 #include <ctype.h>
26 #include <iconv.h>
27 #include <stdbool.h>
28
29 typedef struct
30 {
31 PyObject_HEAD
32 ppd_option_t *option;
33 PPD *ppd;
34 } Option;
35
36 typedef struct
37 {
38 PyObject_HEAD
39 ppd_const_t *constraint;
40 PPD *ppd;
41 } Constraint;
42
43 typedef struct
44 {
45 PyObject_HEAD
46 ppd_group_t *group;
47 PPD *ppd;
48 } Group;
49
50 typedef struct
51 {
52 PyObject_HEAD
53 ppd_attr_t *attribute;
54 PPD *ppd;
55 } Attribute;
56
57 /////////////////////////
58 // Encoding conversion //
59 /////////////////////////
60
61 static int
ppd_encoding_is_utf8(PPD * ppd)62 ppd_encoding_is_utf8 (PPD *ppd)
63 {
64 const char *lang_encoding, *from_encoding;
65 iconv_t cdf, cdt;
66 if (ppd->conv_from != NULL)
67 return 0;
68
69 lang_encoding = ppd->ppd->lang_encoding;
70 if (lang_encoding && !strcasecmp (lang_encoding, "UTF-8"))
71 return 1;
72
73 if (lang_encoding && !strcasecmp (lang_encoding, "ISOLatin1"))
74 from_encoding = "ISO-8859-1";
75 else if (lang_encoding && !strcasecmp (lang_encoding, "ISOLatin2"))
76 from_encoding = "ISO-8859-2";
77 else if (lang_encoding && !strcasecmp (lang_encoding, "ISOLatin5"))
78 from_encoding = "ISO-8859-5";
79 else if (lang_encoding && !strcasecmp (lang_encoding, "JIS83-RKSJ"))
80 from_encoding = "SHIFT-JIS";
81 else if (lang_encoding && !strcasecmp (lang_encoding, "MacStandard"))
82 from_encoding = "MACINTOSH";
83 else if (lang_encoding && !strcasecmp (lang_encoding, "WindowsANSI"))
84 from_encoding = "WINDOWS-1252";
85 else
86 // Guess
87 from_encoding = "ISO-8859-1";
88
89 cdf = iconv_open ("UTF-8", from_encoding);
90 if (cdf == (iconv_t) -1)
91 cdf = iconv_open ("UTF-8", "ISO-8859-1");
92
93 cdt = iconv_open (from_encoding, "UTF-8");
94 if (cdt == (iconv_t) -1)
95 cdt = iconv_open ("ISO-8859-1", "UTF-8");
96
97 ppd->conv_from = malloc (sizeof (iconv_t));
98 *ppd->conv_from = cdf;
99
100 ppd->conv_to = malloc (sizeof (iconv_t));
101 *ppd->conv_to = cdt;
102
103 return 0;
104 }
105
106 static PyObject *
cautious_PyUnicode_DecodeUTF8(const char * str,size_t len)107 cautious_PyUnicode_DecodeUTF8 (const char *str, size_t len)
108 {
109 PyObject *ret = PyUnicode_DecodeUTF8 (str, len, NULL);
110 if (ret == NULL) {
111 // It wasn't UTF-8 after all. Just make the string safe for ASCII.
112 char *safe;
113 size_t i;
114
115 PyErr_Clear ();
116 safe = malloc (len + 1);
117 for (i = 0; i < len; i++) {
118 unsigned char ch = str[i];
119 if (!isascii (ch))
120 ch = '?';
121
122 safe[i] = ch;
123 }
124 safe[i] = '\0';
125 ret = PyUnicode_DecodeUTF8 (safe, len, NULL);
126 printf ("Bad UTF-8 string \"%s\" changed to \"%s\"\n", str, safe);
127 free (safe);
128 }
129
130 return ret;
131 }
132
133 static PyObject *
make_PyUnicode_from_ppd_string(PPD * ppd,const char * ppdstr)134 make_PyUnicode_from_ppd_string (PPD *ppd, const char *ppdstr)
135 {
136 iconv_t cdf;
137 size_t len;
138 char *outbuf, *outbufptr;
139 size_t outbytesleft;
140 size_t origleft;
141 PyObject *ret;
142
143 if (ppd_encoding_is_utf8 (ppd))
144 return cautious_PyUnicode_DecodeUTF8 (ppdstr, strlen (ppdstr));
145
146 cdf = *ppd->conv_from;
147
148 // Reset to initial state
149 iconv (cdf, NULL, NULL, NULL, NULL);
150 len = strlen (ppdstr); // CUPS doesn't keep track of string lengths
151 origleft = outbytesleft = MB_CUR_MAX * len;
152 outbufptr = outbuf = malloc (outbytesleft);
153 if (iconv (cdf, (char **) &ppdstr, &len,
154 &outbufptr, &outbytesleft) == (size_t) -1) {
155 free (outbuf);
156 return PyErr_SetFromErrno (PyExc_RuntimeError);
157 }
158
159 ret = cautious_PyUnicode_DecodeUTF8 (outbuf, origleft - outbytesleft);
160 free (outbuf);
161 return ret;
162 }
163
164 static char *
utf8_to_ppd_encoding(PPD * ppd,const char * inbuf)165 utf8_to_ppd_encoding (PPD *ppd, const char *inbuf)
166 {
167 char *outbuf, *ret;
168 size_t len, outsize, outbytesleft;
169 iconv_t cdt;
170
171 if (ppd_encoding_is_utf8 (ppd))
172 return strdup (inbuf);
173
174 cdt = *ppd->conv_to;
175
176 // Reset to initial state
177 iconv (cdt, NULL, NULL, NULL, NULL);
178 len = strlen (inbuf);
179 outsize = 1 + 6 * len;
180 outbytesleft = outsize - 1;
181 ret = outbuf = malloc (outsize);
182 if (iconv (cdt, (char **) &inbuf, &len,
183 &outbuf, &outbytesleft) == (size_t) -1) {
184 free (outbuf);
185 return NULL;
186 }
187 *outbuf = '\0';
188
189 return ret;
190 }
191
192 /////////
193 // PPD //
194 /////////
195
196 static PyObject *
PPD_new(PyTypeObject * type,PyObject * args,PyObject * kwds)197 PPD_new (PyTypeObject *type, PyObject *args, PyObject *kwds)
198 {
199 PPD *self;
200 self = (PPD *) type->tp_alloc (type, 0);
201 if (self != NULL) {
202 self->ppd = NULL;
203 self->file = NULL;
204 self->conv_from = NULL;
205 self->conv_to = NULL;
206 }
207
208 return (PyObject *) self;
209 }
210
211 static int
PPD_init(PPD * self,PyObject * args,PyObject * kwds)212 PPD_init (PPD *self, PyObject *args, PyObject *kwds)
213 {
214 PyObject *filenameobj;
215 char *filename;
216
217 if (!PyArg_ParseTuple (args, "O", &filenameobj))
218 return -1;
219
220 if (UTF8_from_PyObj (&filename, filenameobj) == NULL)
221 return -1;
222
223 self->file = fopen (filename, "r");
224 if (!self->file) {
225 PyErr_SetString (PyExc_RuntimeError, "fopen failed");
226 free (filename);
227 return -1;
228 }
229
230 debugprintf ("+ PPD %p %s (fd %d)\n", self, filename, fileno (self->file));
231 self->ppd = ppdOpenFile (filename);
232 free (filename);
233 if (!self->ppd) {
234 fclose (self->file);
235 self->file = NULL;
236 PyErr_SetString (PyExc_RuntimeError, "ppdOpenFile failed");
237 return -1;
238 }
239 self->conv_from = self->conv_to = NULL;
240
241 return 0;
242 }
243
244 static void
PPD_dealloc(PPD * self)245 PPD_dealloc (PPD *self)
246 {
247 if (self->file) {
248 debugprintf ("- PPD %p (fd %d)\n", self, fileno (self->file));
249 fclose (self->file);
250 } else
251 debugprintf ("- PPD %p (no fd)\n", self);
252
253 if (self->ppd)
254 ppdClose (self->ppd);
255 if (self->conv_from)
256 iconv_close (*self->conv_from);
257 if (self->conv_to)
258 iconv_close (*self->conv_to);
259
260 ((PyObject *)self)->ob_type->tp_free ((PyObject *) self);
261 }
262
263 /////////
264 // PPD // METHODS
265 /////////
266
267 static PyObject *
PPD_localize(PPD * self)268 PPD_localize (PPD *self)
269 {
270 if (!ppdLocalize (self->ppd))
271 Py_RETURN_NONE;
272 return PyErr_SetFromErrno (PyExc_RuntimeError);
273 }
274
275 static PyObject *
PPD_localizeIPPReason(PPD * self,PyObject * args,PyObject * kwds)276 PPD_localizeIPPReason (PPD *self, PyObject *args, PyObject *kwds)
277 {
278 PyObject *ret;
279 PyObject *reasonobj;
280 PyObject *schemeobj = NULL;
281 char *reason;
282 char *scheme = NULL;
283 char *buffer;
284 const size_t bufsize = 1024;
285 static char *kwlist[] = { "reason", "scheme", NULL };
286
287 if (!PyArg_ParseTupleAndKeywords (args, kwds, "O|O", kwlist,
288 &reasonobj, &schemeobj))
289 return NULL;
290
291 if (UTF8_from_PyObj (&reason, reasonobj) == NULL)
292 return NULL;
293
294 if (schemeobj)
295 if (UTF8_from_PyObj (&scheme, schemeobj) == NULL) {
296 free (reason);
297 return NULL;
298 }
299
300 buffer = malloc (bufsize);
301 if (ppdLocalizeIPPReason (self->ppd, reason, scheme, buffer, bufsize))
302 {
303 ret = make_PyUnicode_from_ppd_string (self, buffer);
304 } else {
305 Py_RETURN_NONE;
306 }
307
308 free (reason);
309 if (scheme)
310 free (scheme);
311 free (buffer);
312 return ret;
313 }
314
315 static PyObject *
PPD_localizeMarkerName(PPD * self,PyObject * args)316 PPD_localizeMarkerName (PPD *self, PyObject *args)
317 {
318 PyObject *ret;
319 PyObject *nameobj;
320 char *name;
321 const char *lname;
322
323 if (!PyArg_ParseTuple (args, "O", &nameobj))
324 return NULL;
325
326 if (UTF8_from_PyObj (&name, nameobj) == NULL)
327 return NULL;
328
329 lname = ppdLocalizeMarkerName (self->ppd, name);
330 free (name);
331
332 if (lname != NULL)
333 {
334 ret = make_PyUnicode_from_ppd_string (self, lname);
335 } else {
336 Py_RETURN_NONE;
337 }
338
339 return ret;
340 }
341
342 static PyObject *
PPD_markDefaults(PPD * self)343 PPD_markDefaults (PPD *self)
344 {
345 ppdMarkDefaults (self->ppd);
346 Py_RETURN_NONE;
347 }
348
349 static PyObject *
PPD_markOption(PPD * self,PyObject * args)350 PPD_markOption (PPD *self, PyObject *args)
351 {
352 int conflicts;
353 char *name, *value;
354 char *encname, *encvalue;
355 if (!PyArg_ParseTuple (args, "eses", "UTF-8", &name, "UTF-8", &value))
356 return NULL;
357
358 encname = utf8_to_ppd_encoding (self, name);
359 PyMem_Free (name);
360 if (!encname) {
361 PyMem_Free (value);
362 return PyErr_SetFromErrno (PyExc_RuntimeError);
363 }
364
365 encvalue = utf8_to_ppd_encoding (self, value);
366 PyMem_Free (value);
367 if (!encvalue) {
368 free (encname);
369 return PyErr_SetFromErrno (PyExc_RuntimeError);
370 }
371
372 conflicts = ppdMarkOption (self->ppd, encname, encvalue);
373 free (encname);
374 free (encvalue);
375 return Py_BuildValue ("i", conflicts);
376 }
377
378 static PyObject *
PPD_conflicts(PPD * self)379 PPD_conflicts (PPD *self)
380 {
381 return PyLong_FromLong (ppdConflicts (self->ppd));
382 }
383
384 static PyObject *
PPD_findOption(PPD * self,PyObject * args)385 PPD_findOption (PPD *self, PyObject *args)
386 {
387 PyObject *ret;
388 PyObject *optionobj;
389 char *option;
390 ppd_option_t *opt;
391
392 if (!PyArg_ParseTuple (args, "O", &optionobj))
393 return NULL;
394
395 if (UTF8_from_PyObj (&option, optionobj) == NULL)
396 return NULL;
397
398 opt = ppdFindOption (self->ppd, option);
399 free (option);
400 if (opt) {
401 PyObject *args = Py_BuildValue ("()");
402 PyObject *kwlist = Py_BuildValue ("{}");
403 Option *optobj = (Option *) PyType_GenericNew (&cups_OptionType,
404 args, kwlist);
405 Py_DECREF (args);
406 Py_DECREF (kwlist);
407 optobj->option = opt;
408 optobj->ppd = self;
409 Py_INCREF (self);
410 ret = (PyObject *) optobj;
411 } else {
412 Py_RETURN_NONE;
413 }
414
415 return ret;
416 }
417
418 static PyObject *
PPD_findAttr(PPD * self,PyObject * args,PyObject * kwds)419 PPD_findAttr (PPD *self, PyObject *args, PyObject *kwds)
420 {
421 PyObject *ret;
422 PyObject *nameobj;
423 PyObject *specobj = NULL;
424 char *name;
425 char *spec = NULL;
426 ppd_attr_t *attr;
427 static char *kwlist[] = { "name", "spec", NULL };
428
429 if (!PyArg_ParseTupleAndKeywords (args, kwds, "O|O", kwlist,
430 &nameobj, &specobj))
431 return NULL;
432
433 if (UTF8_from_PyObj (&name, nameobj) == NULL)
434 return NULL;
435
436 if (specobj)
437 if (UTF8_from_PyObj (&spec, specobj) == NULL) {
438 free (name);
439 return NULL;
440 }
441
442 attr = ppdFindAttr (self->ppd, name, spec);
443 free (name);
444 if (spec)
445 free (spec);
446 if (attr) {
447 PyObject *largs = Py_BuildValue ("()");
448 PyObject *lkwlist = Py_BuildValue ("{}");
449 Attribute *attrobj = (Attribute *) PyType_GenericNew (&cups_AttributeType,
450 largs, lkwlist);
451 Py_DECREF (largs);
452 Py_DECREF (lkwlist);
453 attrobj->attribute = attr;
454 attrobj->ppd = self;
455 Py_INCREF (self);
456 ret = (PyObject *) attrobj;
457 } else {
458 Py_RETURN_NONE;
459 }
460
461 return ret;
462 }
463
464 static PyObject *
PPD_findNextAttr(PPD * self,PyObject * args,PyObject * kwds)465 PPD_findNextAttr (PPD *self, PyObject *args, PyObject *kwds)
466 {
467 PyObject *ret;
468 PyObject *nameobj;
469 PyObject *specobj = NULL;
470 char *name;
471 char *spec = NULL;
472 ppd_attr_t *attr;
473 static char *kwlist[] = { "name", "spec", NULL };
474
475 if (!PyArg_ParseTupleAndKeywords (args, kwds, "O|O", kwlist,
476 &nameobj, &specobj))
477 return NULL;
478
479 if (UTF8_from_PyObj (&name, nameobj) == NULL)
480 return NULL;
481
482 if (specobj)
483 if (UTF8_from_PyObj (&spec, specobj) == NULL) {
484 free (name);
485 return NULL;
486 }
487
488 attr = ppdFindNextAttr (self->ppd, name, spec);
489 free (name);
490 if (spec)
491 free (spec);
492 if (attr) {
493 PyObject *largs = Py_BuildValue ("()");
494 PyObject *lkwlist = Py_BuildValue ("{}");
495 Attribute *attrobj = (Attribute *) PyType_GenericNew (&cups_AttributeType,
496 largs, lkwlist);
497 Py_DECREF (largs);
498 Py_DECREF (lkwlist);
499 attrobj->attribute = attr;
500 attrobj->ppd = self;
501 Py_INCREF (self);
502 ret = (PyObject *) attrobj;
503 } else {
504 Py_RETURN_NONE;
505 }
506
507 return ret;
508 }
509
510 static int
nondefaults_are_marked(ppd_group_t * g)511 nondefaults_are_marked (ppd_group_t *g)
512 {
513 ppd_option_t *o;
514 int oi;
515 for (oi = 0, o = g->options;
516 oi < g->num_options;
517 oi++, o++) {
518 ppd_choice_t *c;
519 int ci;
520 for (ci = 0, c = o->choices;
521 ci < o->num_choices;
522 ci++, c++) {
523 if (c->marked) {
524 if (strcmp (c->choice, o->defchoice))
525 return 1;
526 break;
527 }
528 }
529 }
530
531 return 0;
532 }
533
534 static PyObject *
PPD_nondefaultsMarked(PPD * self)535 PPD_nondefaultsMarked (PPD *self)
536 {
537 int nondefaults_marked = 0;
538 ppd_group_t *g;
539 int gi;
540 for (gi = 0, g = self->ppd->groups;
541 gi < self->ppd->num_groups && !nondefaults_marked;
542 gi++, g++) {
543 ppd_group_t *sg;
544 int sgi;
545 if (nondefaults_are_marked (g)) {
546 nondefaults_marked = 1;
547 break;
548 }
549
550 for (sgi = 0, sg = g->subgroups;
551 sgi < g->num_subgroups;
552 sgi++, sg++) {
553 if (nondefaults_are_marked (sg)) {
554 nondefaults_marked = 1;
555 break;
556 }
557 }
558 }
559
560 return PyBool_FromLong (nondefaults_marked);
561 }
562
563 #if !(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
564 /*
565 * A rudimentary emulation of getline() for systems that dont support it
566 * natively. Since this is used for PPD file reading, it assumes (possibly
567 * falsely) that BUFSIZ is big enough.
568 */
569 ssize_t
getline(char ** line,size_t * linelen,FILE * fp)570 getline(char **line, size_t *linelen, FILE *fp)
571 {
572 if (*linelen == 0) {
573 *linelen = BUFSIZ;
574 *line = malloc(*linelen);
575 }
576
577 memset(*line, 0, *linelen);
578 fgets(*line, *linelen, fp);
579
580 return (strlen(*line));
581 }
582 #endif
583
584 /*
585 * emit marked options by returning a string.
586 */
587
588 static PyObject *
PPD_emitString(PPD * self,PyObject * args)589 PPD_emitString (PPD *self, PyObject *args)
590 {
591 ppd_section_t section;
592 float min_order;
593 char *emitted;
594 PyObject *ret;
595
596 if (!PyArg_ParseTuple (args, "if", §ion, &min_order))
597 return NULL;
598
599 emitted = ppdEmitString(self->ppd, section, min_order);
600
601 if (emitted) {
602 ret = PyUnicode_FromString (emitted);
603 free (emitted);
604 } else {
605 Py_RETURN_NONE;
606 }
607
608 return ret;
609 }
610
611 /*
612 * emit marked options by writing to a file object.
613 */
614
615 static PyObject *
PPD_emit(PPD * self,PyObject * args)616 PPD_emit (PPD *self, PyObject *args)
617 {
618 PyObject *pyFile;
619 ppd_section_t section;
620 FILE *f;
621
622 if (!PyArg_ParseTuple (args, "Oi", &pyFile, §ion))
623 return NULL;
624
625 int fd = PyObject_AsFileDescriptor(pyFile);
626 f = fdopen(fd, "w");
627 if (!f)
628 return PyErr_SetFromErrno (PyExc_RuntimeError);
629
630 if (!ppdEmit(self->ppd, f, section))
631 Py_RETURN_NONE;
632 return PyErr_SetFromErrno (PyExc_RuntimeError);
633 }
634
635 /*
636 * emit marked options after order dependency by writing to a file object.
637 */
638
639 static PyObject *
PPD_emitAfterOrder(PPD * self,PyObject * args)640 PPD_emitAfterOrder (PPD *self, PyObject *args)
641 {
642 PyObject *pyFile;
643 ppd_section_t section;
644 FILE *f;
645 int limit;
646 float min_order;
647
648 if (!PyArg_ParseTuple (args, "Oiif", &pyFile, §ion, &limit, &min_order))
649 return NULL;
650
651 int fd = PyObject_AsFileDescriptor(pyFile);
652 f = fdopen(fd, "w");
653 if (!f)
654 return PyErr_SetFromErrno (PyExc_RuntimeError);
655
656 if (!ppdEmitAfterOrder(self->ppd, f, section, limit, min_order))
657 Py_RETURN_NONE;
658 return PyErr_SetFromErrno (PyExc_RuntimeError);
659 }
660
661 /*
662 * emit marked options by writing to a file descriptor.
663 */
664
665 static PyObject *
PPD_emitFd(PPD * self,PyObject * args)666 PPD_emitFd (PPD *self, PyObject *args)
667 {
668 ppd_section_t section;
669 int f;
670
671 if (!PyArg_ParseTuple (args, "ii", &f, §ion))
672 return NULL;
673
674 if (!ppdEmitFd(self->ppd, f, section))
675 Py_RETURN_NONE;
676 return PyErr_SetFromErrno (PyExc_RuntimeError);
677 }
678
679 /*
680 * emit JCL options by writing to a file object.
681 */
682
683 static PyObject *
PPD_emitJCL(PPD * self,PyObject * args)684 PPD_emitJCL (PPD *self, PyObject *args)
685 {
686 PyObject *pyFile;
687 int job_id;
688 PyObject *userobj;
689 PyObject *titleobj;
690 char *user;
691 char *title;
692 FILE *f;
693
694 if (!PyArg_ParseTuple (args, "OiOO", &pyFile, &job_id, &userobj, &titleobj))
695 return NULL;
696
697 if (UTF8_from_PyObj (&user, userobj) == NULL)
698 return NULL;
699
700 if (UTF8_from_PyObj (&title, titleobj) == NULL) {
701 free (user);
702 return NULL;
703 }
704
705 int fd = PyObject_AsFileDescriptor(pyFile);
706 f = fdopen(fd, "w");
707 if (!f)
708 return PyErr_SetFromErrno (PyExc_RuntimeError);
709
710 if (!ppdEmitJCL(self->ppd, f, job_id, user, title))
711 Py_RETURN_NONE;
712
713 free (user);
714 free (title);
715 return PyErr_SetFromErrno (PyExc_RuntimeError);
716 }
717
718 /*
719 * emit JCL end by writing to a file object.
720 */
721
722 static PyObject *
PPD_emitJCLEnd(PPD * self,PyObject * args)723 PPD_emitJCLEnd (PPD *self, PyObject *args)
724 {
725 PyObject *pyFile;
726 FILE *f;
727
728 if (!PyArg_ParseTuple (args, "O", &pyFile))
729 return NULL;
730
731 int fd = PyObject_AsFileDescriptor(pyFile);
732 f = fdopen(fd, "w");
733 if (!f)
734 return PyErr_SetFromErrno (PyExc_RuntimeError);
735
736 if (!ppdEmitJCLEnd(self->ppd, f))
737 Py_RETURN_NONE;
738 return PyErr_SetFromErrno (PyExc_RuntimeError);
739 }
740
741 PyObject *
PPD_writeFd(PPD * self,PyObject * args)742 PPD_writeFd (PPD *self, PyObject *args)
743 {
744 char *line = NULL;
745 size_t linelen = 0;
746 FILE *out;
747 int fd;
748 int dfd;
749 if (!PyArg_ParseTuple (args, "i", &fd))
750 return NULL;
751
752 dfd = dup (fd);
753 if (dfd == -1)
754 return PyErr_SetFromErrno (PyExc_RuntimeError);
755
756 out = fdopen (dfd, "w");
757 if (!out)
758 return PyErr_SetFromErrno (PyExc_RuntimeError);
759
760 rewind (self->file);
761 while (!feof (self->file)) {
762 int written = 0;
763 ssize_t got = getline (&line, &linelen, self->file);
764 if (got == -1)
765 break;
766
767 if (!strncmp (line, "*Default", 8)) {
768 char *keyword;
769 char *start = line + 8;
770 char *end;
771 ppd_choice_t *choice;
772 for (end = start; *end; end++)
773 if (isspace (*end) || *end == ':')
774 break;
775 keyword = calloc(1, (end - start) + 1);
776 strncpy(keyword, start, end - start);
777 choice = ppdFindMarkedChoice (self->ppd, keyword);
778
779 // Treat PageRegion, PaperDimension and ImageableArea specially:
780 // if not marked, use PageSize option.
781 if (!choice && (!strcmp (keyword, "PageRegion") ||
782 !strcmp (keyword, "PaperDimension") ||
783 !strcmp (keyword, "ImageableArea")))
784 choice = ppdFindMarkedChoice (self->ppd, "PageSize");
785
786 if (choice) {
787 fprintf (out, "*Default%s: %s", keyword, choice->choice);
788 if (strchr (end, '\r'))
789 fputs ("\r", out);
790 fputs ("\n", out);
791 written = 1;
792 }
793 }
794
795 if (!written)
796 fputs (line, out);
797 }
798
799 fclose (out);
800 if (line)
801 free (line);
802
803 Py_RETURN_NONE;
804 }
805
806 /////////
807 // PPD // ATTRIBUTES
808 /////////
809
810 static PyObject *
PPD_getConstraints(PPD * self,void * closure)811 PPD_getConstraints (PPD *self, void *closure)
812 {
813 PyObject *ret = PyList_New (0);
814 ppd_const_t *c;
815 int i;
816 for (i = 0, c = self->ppd->consts;
817 i < self->ppd->num_consts;
818 i++, c++) {
819 PyObject *args = Py_BuildValue ("()");
820 PyObject *kwlist = Py_BuildValue ("{}");
821 Constraint *cns = (Constraint *) PyType_GenericNew (&cups_ConstraintType,
822 args, kwlist);
823 Py_DECREF (args);
824 Py_DECREF (kwlist);
825 cns->constraint = c;
826 cns->ppd = self;
827 Py_INCREF (self);
828 PyList_Append (ret, (PyObject *) cns);
829 }
830
831 return ret;
832 }
833
834 static PyObject *
PPD_getAttributes(PPD * self,void * closure)835 PPD_getAttributes (PPD *self, void *closure)
836 {
837 PyObject *ret = PyList_New (0);
838 int i;
839 for (i = 0; i < self->ppd->num_attrs; i++) {
840 PyObject *args = Py_BuildValue ("()");
841 PyObject *kwlist = Py_BuildValue ("{}");
842 Attribute *as = (Attribute *) PyType_GenericNew (&cups_AttributeType,
843 args, kwlist);
844 ppd_attr_t *a = self->ppd->attrs[i];
845 Py_DECREF (args);
846 Py_DECREF (kwlist);
847 as->attribute = a;
848 as->ppd = self;
849 Py_INCREF (self);
850 PyList_Append (ret, (PyObject *) as);
851 }
852
853 return ret;
854 }
855
856 static PyObject *
PPD_getOptionGroups(PPD * self,void * closure)857 PPD_getOptionGroups (PPD *self, void *closure)
858 {
859 PyObject *ret = PyList_New (0);
860 ppd_group_t *group;
861 int i;
862
863 for (i = 0, group = self->ppd->groups;
864 i < self->ppd->num_groups;
865 i++, group++) {
866 PyObject *args = Py_BuildValue ("()");
867 PyObject *kwlist = Py_BuildValue ("{}");
868 Group *grp = (Group *) PyType_GenericNew (&cups_GroupType,
869 args, kwlist);
870 Py_DECREF (args);
871 Py_DECREF (kwlist);
872 grp->group = group;
873 grp->ppd = self;
874 Py_INCREF (self);
875 PyList_Append (ret, (PyObject *) grp);
876 }
877
878 return ret;
879 }
880
881 PyGetSetDef PPD_getseters[] =
882 {
883 { "constraints",
884 (getter) PPD_getConstraints, (setter) NULL,
885 "List of constraints", NULL },
886
887 { "attributes",
888 (getter) PPD_getAttributes, (setter) NULL,
889 "List of attributes", NULL },
890
891 { "optionGroups",
892 (getter) PPD_getOptionGroups, (setter) NULL,
893 "List of PPD option groups" },
894
895 { NULL }, /* Sentinel */
896 };
897
898 PyMethodDef PPD_methods[] =
899 {
900 { "localize",
901 (PyCFunction) PPD_localize, METH_NOARGS,
902 "localize() -> None\n\n"
903 "Localize PPD to the current locale." },
904
905 { "localizeIPPReason",
906 (PyCFunction) PPD_localizeIPPReason, METH_VARARGS | METH_KEYWORDS,
907 "localizeIPPReason(reason, scheme) -> string or None\n\n"
908 "Localize IPP reason to the current locale." },
909
910 { "localizeMarkerName",
911 (PyCFunction) PPD_localizeMarkerName, METH_VARARGS,
912 "localizeMarkerName(name) -> string or None\n\n"
913 "Localize marker name to the current locale." },
914
915 { "markDefaults",
916 (PyCFunction) PPD_markDefaults, METH_NOARGS,
917 "markDefaults() -> None\n\n"
918 "Set (mark) all options to their default choices." },
919
920 { "markOption",
921 (PyCFunction) PPD_markOption, METH_VARARGS,
922 "markOption(option, choice) -> integer\n\n"
923 "Set an option to a particular choice.\n\n"
924 "@type option: string\n"
925 "@param option: option keyword\n"
926 "@type choice: string\n"
927 "@param choice: option choice\n"
928 "@return: number of conflicts" },
929
930 { "conflicts",
931 (PyCFunction) PPD_conflicts, METH_NOARGS,
932 "conflicts() -> integer\n\n"
933 "@return: number of conflicts." },
934
935 { "findOption",
936 (PyCFunction) PPD_findOption, METH_VARARGS,
937 "findOption(name)\n\n"
938 "@type name: string\n"
939 "@param name: option keyword\n"
940 "@rtype: L{Option} or None\n"
941 "@return: named option, or None if not found." },
942
943 { "findAttr",
944 (PyCFunction) PPD_findAttr, METH_VARARGS | METH_KEYWORDS,
945 "findAttr(name)\n\n"
946 "@type name: string\n"
947 "@param name: attribute name\n"
948 "@type spec: string\n"
949 "@keyword spec: specifier string (optional)\n"
950 "@rtype: L{Attribute} or None\n"
951 "@return: matching attribute, or None if not found." },
952
953 { "findNextAttr",
954 (PyCFunction) PPD_findNextAttr, METH_VARARGS | METH_KEYWORDS,
955 "findNextAttr(name)\n\n"
956 "@type name: string\n"
957 "@param name: attribute name\n"
958 "@type spec: string\n"
959 "@keyword spec: specifier string (optional)\n"
960 "@rtype: L{Attribute} or None\n"
961 "@return: next matching attribute, or None if not found." },
962
963 { "nondefaultsMarked",
964 (PyCFunction) PPD_nondefaultsMarked, METH_NOARGS,
965 "nondefaultsMarked() -> boolean\n\n"
966 "Returns true if any non-default option choices are marked." },
967
968 { "emitString",
969 (PyCFunction) PPD_emitString, METH_VARARGS,
970 "emitString(section, min_order) -> string\n\n"
971 "Return a string with the marked options for section, with at least min_order order dependency.\n"
972 "@type section: integer\n"
973 "@param section: section id\n"
974 "@type min_order: float\n"
975 "@param min_order: minimum order dependency\n"
976 "@return: string containing emitted postscript" },
977
978 { "emit",
979 (PyCFunction) PPD_emit, METH_VARARGS,
980 "emit(file, section) -> None\n\n"
981 "Output marked options for section to a file.\n"
982 "@type file: file\n"
983 "@param file: file object\n"
984 "@type section: integer\n"
985 "@param section: section id" },
986
987 { "emitAfterOrder",
988 (PyCFunction) PPD_emitAfterOrder, METH_VARARGS,
989 "emitAfterOrder(file, section, limit, min_order) -> None\n\n"
990 "Output marked options for section to a file.\n"
991 "@type file: file\n"
992 "@param file: file object\n"
993 "@type section: integer\n"
994 "@param section: section id\n"
995 "@type limit: integer\n"
996 "@param limit: non-zero to use min_order\n"
997 "@type min_order: float\n"
998 "@param min_order: minimum order dependency" },
999
1000 { "emitFd",
1001 (PyCFunction) PPD_emitFd, METH_VARARGS,
1002 "emitFd(fd, section) -> None\n\n"
1003 "Output marked options for section to a file descriptor.\n"
1004 "@type fd: integer\n"
1005 "@param fd: file descriptor\n"
1006 "@type section: integer\n"
1007 "@param section: section id" },
1008
1009 { "emitJCL",
1010 (PyCFunction) PPD_emitJCL, METH_VARARGS,
1011 "emitJCL(file, job_id, user, title) -> None\n\n"
1012 "Emit code for JCL options to a file.\n"
1013 "@type file: file object\n"
1014 "@param file: file\n"
1015 "@type job_id: integer\n"
1016 "@param job_id: job id\n"
1017 "@type user: string\n"
1018 "@param user: user name on job\n"
1019 "@type title: string\n"
1020 "@param title: title of job" },
1021
1022 { "emitJCLEnd",
1023 (PyCFunction) PPD_emitJCLEnd, METH_VARARGS,
1024 "emitJCLEnd(file) -> None\n\n"
1025 "Emit JCLEnd code to a file.\n"
1026 "@type file: file object\n"
1027 "@param file: file" },
1028
1029 { "writeFd",
1030 (PyCFunction) PPD_writeFd, METH_VARARGS,
1031 "writeFd(fd) -> None\n\n"
1032 "Write PPD file, with marked choices as defaults, to file\n"
1033 "descriptor.\n\n"
1034 "@type fd: integer\n"
1035 "@param fd: open file descriptor" },
1036
1037 { NULL } /* Sentinel */
1038 };
1039
1040 PyTypeObject cups_PPDType =
1041 {
1042 PyVarObject_HEAD_INIT(NULL, 0)
1043 "cups.PPD", /*tp_name*/
1044 sizeof(PPD), /*tp_basicsize*/
1045 0, /*tp_itemsize*/
1046 (destructor)PPD_dealloc, /*tp_dealloc*/
1047 0, /*tp_print*/
1048 0, /*tp_getattr*/
1049 0, /*tp_setattr*/
1050 0, /*tp_compare*/
1051 0, /*tp_repr*/
1052 0, /*tp_as_number*/
1053 0, /*tp_as_sequence*/
1054 0, /*tp_as_mapping*/
1055 0, /*tp_hash */
1056 0, /*tp_call*/
1057 0, /*tp_str*/
1058 0, /*tp_getattro*/
1059 0, /*tp_setattro*/
1060 0, /*tp_as_buffer*/
1061 Py_TPFLAGS_DEFAULT, /*tp_flags*/
1062 "PPD file\n"
1063 "========\n"
1064 " A PPD file.\n\n"
1065 "@type constraints: L{Constraint} list\n"
1066 "@ivar constraints: list of constraints\n"
1067 "@type attributes: L{Attribute} list\n"
1068 "@ivar attributes: list of attributes\n"
1069 "@type optionGroups: L{Group} list\n"
1070 "@ivar optionGroups: list of PPD option groups\n"
1071 "", /* tp_doc */
1072 0, /* tp_traverse */
1073 0, /* tp_clear */
1074 0, /* tp_richcompare */
1075 0, /* tp_weaklistoffset */
1076 0, /* tp_iter */
1077 0, /* tp_iternext */
1078 PPD_methods, /* tp_methods */
1079 0, /* tp_members */
1080 PPD_getseters, /* tp_getset */
1081 0, /* tp_base */
1082 0, /* tp_dict */
1083 0, /* tp_descr_get */
1084 0, /* tp_descr_set */
1085 0, /* tp_dictoffset */
1086 (initproc)PPD_init, /* tp_init */
1087 0, /* tp_alloc */
1088 PPD_new, /* tp_new */
1089 };
1090
1091 ////////////
1092 // Option //
1093 ////////////
1094
1095 static PyObject *
Option_new(PyTypeObject * type,PyObject * args,PyObject * kwds)1096 Option_new (PyTypeObject *type, PyObject *args, PyObject *kwds)
1097 {
1098 Option *self;
1099 self = (Option *) type->tp_alloc (type, 0);
1100 return (PyObject *) self;
1101 }
1102
1103 static int
Option_init(Option * self,PyObject * args,PyObject * kwds)1104 Option_init (Option *self, PyObject *args, PyObject *kwds)
1105 {
1106 self->option = NULL;
1107 return 0;
1108 }
1109
1110 static void
Option_dealloc(Option * self)1111 Option_dealloc (Option *self)
1112 {
1113 Py_XDECREF (self->ppd);
1114 ((PyObject *)self)->ob_type->tp_free ((PyObject *) self);
1115 }
1116
1117 static PyObject *
Option_repr(Option * self)1118 Option_repr (Option *self)
1119 {
1120 ppd_option_t *option = self->option;
1121 if (!option)
1122 return PyUnicode_FromString ("<cups.Option>");
1123
1124 char buffer[256];
1125 snprintf (buffer, 256, "<cups.Option %s=%s>",
1126 option->keyword, option->defchoice);
1127 return PyUnicode_FromString (buffer);
1128 }
1129
1130 ////////////
1131 // Option // ATTRIBUTES
1132 ////////////
1133
1134 static PyObject *
Option_getConflicted(Option * self,void * closure)1135 Option_getConflicted (Option *self, void *closure)
1136 {
1137 if (!self->option || self->option->conflicted)
1138 Py_RETURN_TRUE;
1139
1140 Py_RETURN_FALSE;
1141 }
1142
1143 static PyObject *
Option_getKeyword(Option * self,void * closure)1144 Option_getKeyword (Option *self, void *closure)
1145 {
1146 if (!self->option) {
1147 Py_RETURN_NONE;
1148 }
1149
1150 return make_PyUnicode_from_ppd_string (self->ppd, self->option->keyword);
1151 }
1152
1153 static PyObject *
Option_getDefchoice(Option * self,void * closure)1154 Option_getDefchoice (Option *self, void *closure)
1155 {
1156 if (!self->option) {
1157 Py_RETURN_NONE;
1158 }
1159
1160 return make_PyUnicode_from_ppd_string (self->ppd, self->option->defchoice);
1161 }
1162
1163 static PyObject *
Option_getText(Option * self,void * closure)1164 Option_getText (Option *self, void *closure)
1165 {
1166 if (!self->option) {
1167 Py_RETURN_NONE;
1168 }
1169
1170 return make_PyUnicode_from_ppd_string (self->ppd, self->option->text);
1171 }
1172
1173 static PyObject *
Option_getUI(Option * self,void * closure)1174 Option_getUI (Option *self, void *closure)
1175 {
1176 if (!self->option) {
1177 Py_RETURN_NONE;
1178 }
1179
1180 return PyLong_FromLong (self->option->ui);
1181 }
1182
1183 static PyObject *
Option_getChoices(Option * self,void * closure)1184 Option_getChoices (Option *self, void *closure)
1185 {
1186 PyObject *choices = PyList_New (0);
1187 ppd_choice_t *choice;
1188 bool defchoice_seen = false;
1189 int i;
1190
1191 if (!self->option)
1192 return choices;
1193
1194 for (i = 0, choice = self->option->choices;
1195 i < self->option->num_choices;
1196 i++, choice++) {
1197 PyObject *choice_dict = PyDict_New ();
1198 PyObject *u;
1199
1200 u = make_PyUnicode_from_ppd_string (self->ppd, choice->choice);
1201 PyDict_SetItemString (choice_dict, "choice", u);
1202 Py_DECREF (u);
1203
1204 u = make_PyUnicode_from_ppd_string (self->ppd, choice->text);
1205 PyDict_SetItemString (choice_dict, "text", u);
1206 Py_DECREF (u);
1207
1208 u = PyBool_FromLong (choice->marked);
1209 PyDict_SetItemString (choice_dict, "marked", u);
1210 Py_DECREF (u);
1211
1212 PyList_Append (choices, choice_dict);
1213 if (!strcmp (choice->choice, self->option->defchoice))
1214 defchoice_seen = true;
1215 }
1216
1217 if (!defchoice_seen) {
1218 // This PPD option has a default choice that isn't one of the choices.
1219 // This really happens.
1220 const char *defchoice = self->option->defchoice;
1221 PyObject *choice_dict = PyDict_New ();
1222 PyObject *u;
1223
1224 u = make_PyUnicode_from_ppd_string (self->ppd, defchoice);
1225 PyDict_SetItemString (choice_dict, "choice", u);
1226 Py_DECREF (u);
1227
1228 u = make_PyUnicode_from_ppd_string (self->ppd, defchoice);
1229 PyDict_SetItemString (choice_dict, "text", u);
1230 Py_DECREF (u);
1231
1232 PyList_Append (choices, choice_dict);
1233 }
1234
1235 return choices;
1236 }
1237
1238 PyGetSetDef Option_getseters[] =
1239 {
1240 { "conflicted",
1241 (getter) Option_getConflicted, (setter) NULL,
1242 "Whether this option is in conflict", NULL },
1243
1244 { "keyword",
1245 (getter) Option_getKeyword, (setter) NULL,
1246 "keyword", NULL },
1247
1248 { "defchoice",
1249 (getter) Option_getDefchoice, (setter) NULL,
1250 "defchoice", NULL },
1251
1252 { "text",
1253 (getter) Option_getText, (setter) NULL,
1254 "text", NULL },
1255
1256 { "ui",
1257 (getter) Option_getUI, (setter) NULL,
1258 "ui", NULL },
1259
1260 { "choices",
1261 (getter) Option_getChoices, (setter) NULL,
1262 "choices", NULL },
1263
1264 { NULL }
1265 };
1266
1267 PyMethodDef Option_methods[] =
1268 {
1269 { NULL } /* Sentinel */
1270 };
1271
1272 PyTypeObject cups_OptionType =
1273 {
1274 PyVarObject_HEAD_INIT(NULL, 0)
1275 "cups.Option", /*tp_name*/
1276 sizeof(Option), /*tp_basicsize*/
1277 0, /*tp_itemsize*/
1278 (destructor)Option_dealloc, /*tp_dealloc*/
1279 0, /*tp_print*/
1280 0, /*tp_getattr*/
1281 0, /*tp_setattr*/
1282 0, /*tp_compare*/
1283 (reprfunc)Option_repr, /*tp_repr*/
1284 0, /*tp_as_number*/
1285 0, /*tp_as_sequence*/
1286 0, /*tp_as_mapping*/
1287 0, /*tp_hash */
1288 0, /*tp_call*/
1289 0, /*tp_str*/
1290 0, /*tp_getattro*/
1291 0, /*tp_setattro*/
1292 0, /*tp_as_buffer*/
1293 Py_TPFLAGS_DEFAULT, /*tp_flags*/
1294 "PPD option\n"
1295 "==========\n"
1296 " A PPD option.\n\n"
1297 "@type conflicted: boolean\n"
1298 "@ivar conflicted: whether this option is in conflict\n"
1299 "@type keyword: string\n"
1300 "@ivar keyword: the option keyword e.g. Duplex\n"
1301 "@type defchoice: string\n"
1302 "@ivar defchoice: the default option choice\n"
1303 "@type text: string\n"
1304 "@ivar text: the user-presentable option name e.g. Double-sided printing\n"
1305 "@type ui: integer\n"
1306 "@ivar ui: the option type; one of L{PPD_UI_BOOLEAN}, \n"
1307 "L{PPD_UI_PICKONE}, L{PPD_UI_PICKMANY}\n"
1308 "@type choices: list\n"
1309 "@ivar choices: list of the option's choices\n"
1310 "", /* tp_doc */
1311 0, /* tp_traverse */
1312 0, /* tp_clear */
1313 0, /* tp_richcompare */
1314 0, /* tp_weaklistoffset */
1315 0, /* tp_iter */
1316 0, /* tp_iternext */
1317 0, /* tp_methods */
1318 0, /* tp_members */
1319 Option_getseters, /* tp_getset */
1320 0, /* tp_base */
1321 0, /* tp_dict */
1322 0, /* tp_descr_get */
1323 0, /* tp_descr_set */
1324 0, /* tp_dictoffset */
1325 (initproc)Option_init, /* tp_init */
1326 0, /* tp_alloc */
1327 Option_new, /* tp_new */
1328 };
1329
1330 ///////////
1331 // Group //
1332 ///////////
1333
1334 static PyObject *
Group_new(PyTypeObject * type,PyObject * args,PyObject * kwds)1335 Group_new (PyTypeObject *type, PyObject *args, PyObject *kwds)
1336 {
1337 Group *self;
1338 self = (Group *) type->tp_alloc (type, 0);
1339 return (PyObject *) self;
1340 }
1341
1342 static int
Group_init(Group * self,PyObject * args,PyObject * kwds)1343 Group_init (Group *self, PyObject *args, PyObject *kwds)
1344 {
1345 self->group = NULL;
1346 return 0;
1347 }
1348
1349 static void
Group_dealloc(Group * self)1350 Group_dealloc (Group *self)
1351 {
1352 Py_XDECREF (self->ppd);
1353 ((PyObject *)self)->ob_type->tp_free ((PyObject *) self);
1354 }
1355
1356 static PyObject *
Group_repr(Group * self)1357 Group_repr (Group *self)
1358 {
1359 ppd_group_t *group = self->group;
1360 if (!group)
1361 return PyUnicode_FromString ("<cups.Group>");
1362
1363 char buffer[256];
1364 snprintf (buffer, 256, "<cups.Group %s>", group->name);
1365 return PyUnicode_FromString (buffer);
1366 }
1367
1368 ///////////
1369 // Group // ATTRIBUTES
1370 ///////////
1371
1372 static PyObject *
Group_getText(Group * self,void * closure)1373 Group_getText (Group *self, void *closure)
1374 {
1375 if (!self->group) {
1376 Py_RETURN_NONE;
1377 }
1378
1379 return make_PyUnicode_from_ppd_string (self->ppd, self->group->text);
1380 }
1381
1382 static PyObject *
Group_getName(Group * self,void * closure)1383 Group_getName (Group *self, void *closure)
1384 {
1385 if (!self->group) {
1386 Py_RETURN_NONE;
1387 }
1388
1389 return make_PyUnicode_from_ppd_string (self->ppd, self->group->name);
1390 }
1391
1392 static PyObject *
Group_getOptions(Group * self,void * closure)1393 Group_getOptions (Group *self, void *closure)
1394 {
1395 PyObject *options = PyList_New (0);
1396 ppd_option_t *option;
1397 int i;
1398
1399 if (!self->group)
1400 return options;
1401
1402 for (i = 0, option = self->group->options;
1403 i < self->group->num_options;
1404 i++, option++) {
1405 PyObject *args = Py_BuildValue ("()");
1406 PyObject *kwlist = Py_BuildValue ("{}");
1407 Option *opt = (Option *) PyType_GenericNew (&cups_OptionType,
1408 args, kwlist);
1409 Py_DECREF (args);
1410 Py_DECREF (kwlist);
1411 opt->option = option;
1412 opt->ppd = self->ppd;
1413 Py_INCREF (self->ppd);
1414 PyList_Append (options, (PyObject *) opt);
1415 }
1416
1417 return options;
1418 }
1419
1420 static PyObject *
Group_getSubgroups(Group * self,void * closure)1421 Group_getSubgroups (Group *self, void *closure)
1422 {
1423 PyObject *subgroups = PyList_New (0);
1424 ppd_group_t *subgroup;
1425 int i;
1426
1427 if (!self->group)
1428 return subgroups;
1429
1430 for (i = 0, subgroup = self->group->subgroups;
1431 i < self->group->num_subgroups;
1432 i++, subgroup++) {
1433 PyObject *args = Py_BuildValue ("()");
1434 PyObject *kwlist = Py_BuildValue ("{}");
1435 Group *grp = (Group *) PyType_GenericNew (&cups_GroupType,
1436 args, kwlist);
1437 Py_DECREF (args);
1438 Py_DECREF (kwlist);
1439 grp->group = subgroup;
1440 grp->ppd = self->ppd;
1441 Py_INCREF (self->ppd);
1442 PyList_Append (subgroups, (PyObject *) grp);
1443 }
1444
1445 return subgroups;
1446 }
1447
1448 PyGetSetDef Group_getseters[] =
1449 {
1450 { "text",
1451 (getter) Group_getText, (setter) NULL,
1452 "text", NULL },
1453
1454 { "name",
1455 (getter) Group_getName, (setter) NULL,
1456 "name", NULL },
1457
1458 { "options",
1459 (getter) Group_getOptions, (setter) NULL,
1460 "options", NULL },
1461
1462 { "subgroups",
1463 (getter) Group_getSubgroups, (setter) NULL,
1464 "subgroups", NULL },
1465
1466 { NULL }
1467 };
1468
1469 PyMethodDef Group_methods[] =
1470 {
1471 { NULL } /* Sentinel */
1472 };
1473
1474 PyTypeObject cups_GroupType =
1475 {
1476 PyVarObject_HEAD_INIT(NULL, 0)
1477 "cups.Group", /*tp_name*/
1478 sizeof(Group), /*tp_basicsize*/
1479 0, /*tp_itemsize*/
1480 (destructor)Group_dealloc, /*tp_dealloc*/
1481 0, /*tp_print*/
1482 0, /*tp_getattr*/
1483 0, /*tp_setattr*/
1484 0, /*tp_compare*/
1485 (reprfunc)Group_repr, /*tp_repr*/
1486 0, /*tp_as_number*/
1487 0, /*tp_as_sequence*/
1488 0, /*tp_as_mapping*/
1489 0, /*tp_hash */
1490 0, /*tp_call*/
1491 0, /*tp_str*/
1492 0, /*tp_getattro*/
1493 0, /*tp_setattro*/
1494 0, /*tp_as_buffer*/
1495 Py_TPFLAGS_DEFAULT, /*tp_flags*/
1496 "PPD option group\n"
1497 "================\n\n"
1498 " A PPD option group.\n\n"
1499 "@type text: string\n"
1500 "@ivar text: user-presentable group name\n"
1501 "@type name: string\n"
1502 "@ivar name: unique group name\n"
1503 "@type options: L{Option} list\n"
1504 "@ivar options: list of options in the group\n"
1505 "@type subgroups: L{Group} list\n"
1506 "@ivar subgroups: list of subgroups in the group\n"
1507 "", /* tp_doc */
1508 0, /* tp_traverse */
1509 0, /* tp_clear */
1510 0, /* tp_richcompare */
1511 0, /* tp_weaklistoffset */
1512 0, /* tp_iter */
1513 0, /* tp_iternext */
1514 0, /* tp_methods */
1515 0, /* tp_members */
1516 Group_getseters, /* tp_getset */
1517 0, /* tp_base */
1518 0, /* tp_dict */
1519 0, /* tp_descr_get */
1520 0, /* tp_descr_set */
1521 0, /* tp_dictoffset */
1522 (initproc)Group_init, /* tp_init */
1523 0, /* tp_alloc */
1524 Group_new, /* tp_new */
1525 };
1526
1527 ////////////////
1528 // Constraint //
1529 ////////////////
1530
1531 static PyObject *
Constraint_new(PyTypeObject * type,PyObject * args,PyObject * kwds)1532 Constraint_new (PyTypeObject *type, PyObject *args, PyObject *kwds)
1533 {
1534 Constraint *self;
1535 self = (Constraint *) type->tp_alloc (type, 0);
1536 return (PyObject *) self;
1537 }
1538
1539 static int
Constraint_init(Constraint * self,PyObject * args,PyObject * kwds)1540 Constraint_init (Constraint *self, PyObject *args, PyObject *kwds)
1541 {
1542 self->constraint = NULL;
1543 return 0;
1544 }
1545
1546 static void
Constraint_dealloc(Constraint * self)1547 Constraint_dealloc (Constraint *self)
1548 {
1549 Py_XDECREF (self->ppd);
1550 ((PyObject *)self)->ob_type->tp_free ((PyObject *) self);
1551 }
1552
1553 ////////////////
1554 // Constraint // ATTRIBUTES
1555 ////////////////
1556
1557 static PyObject *
Constraint_getOption1(Constraint * self,void * closure)1558 Constraint_getOption1 (Constraint *self, void *closure)
1559 {
1560 if (!self->constraint) {
1561 Py_RETURN_NONE;
1562 }
1563
1564 return make_PyUnicode_from_ppd_string (self->ppd, self->constraint->option1);
1565 }
1566
1567 static PyObject *
Constraint_getChoice1(Constraint * self,void * closure)1568 Constraint_getChoice1 (Constraint *self, void *closure)
1569 {
1570 if (!self->constraint) {
1571 Py_RETURN_NONE;
1572 }
1573
1574 return make_PyUnicode_from_ppd_string (self->ppd, self->constraint->choice1);
1575 }
1576
1577 static PyObject *
Constraint_getOption2(Constraint * self,void * closure)1578 Constraint_getOption2 (Constraint *self, void *closure)
1579 {
1580 if (!self->constraint) {
1581 Py_RETURN_NONE;
1582 }
1583
1584 return make_PyUnicode_from_ppd_string (self->ppd, self->constraint->option2);
1585 }
1586
1587 static PyObject *
Constraint_getChoice2(Constraint * self,void * closure)1588 Constraint_getChoice2 (Constraint *self, void *closure)
1589 {
1590 if (!self->constraint) {
1591 Py_RETURN_NONE;
1592 }
1593
1594 return make_PyUnicode_from_ppd_string (self->ppd, self->constraint->choice2);
1595 }
1596
1597 PyGetSetDef Constraint_getseters[] =
1598 {
1599 { "option1",
1600 (getter) Constraint_getOption1, (setter) NULL,
1601 "option1", NULL },
1602
1603 { "choice1",
1604 (getter) Constraint_getChoice1, (setter) NULL,
1605 "choice1", NULL },
1606
1607 { "option2",
1608 (getter) Constraint_getOption2, (setter) NULL,
1609 "option2", NULL },
1610
1611 { "choice2",
1612 (getter) Constraint_getChoice2, (setter) NULL,
1613 "choice2", NULL },
1614
1615 { NULL }
1616 };
1617
1618 PyTypeObject cups_ConstraintType =
1619 {
1620 PyVarObject_HEAD_INIT(NULL, 0)
1621 "cups.Constraint", /*tp_name*/
1622 sizeof(Constraint), /*tp_basicsize*/
1623 0, /*tp_itemsize*/
1624 (destructor)Constraint_dealloc, /*tp_dealloc*/
1625 0, /*tp_print*/
1626 0, /*tp_getattr*/
1627 0, /*tp_setattr*/
1628 0, /*tp_compare*/
1629 0, /*tp_repr*/
1630 0, /*tp_as_number*/
1631 0, /*tp_as_sequence*/
1632 0, /*tp_as_mapping*/
1633 0, /*tp_hash */
1634 0, /*tp_call*/
1635 0, /*tp_str*/
1636 0, /*tp_getattro*/
1637 0, /*tp_setattro*/
1638 0, /*tp_as_buffer*/
1639 Py_TPFLAGS_DEFAULT, /*tp_flags*/
1640 "PPD constraint\n"
1641 "==============\n\n"
1642 " A PPD constraint.\n\n"
1643 "@type option1: string\n"
1644 "@ivar option1: first option keyword\n"
1645 "@type choice1: string\n"
1646 "@ivar choice1: first option choice\n"
1647 "@type option2: string\n"
1648 "@ivar option2: second option keyword\n"
1649 "@type choice2: string\n"
1650 "@ivar choice2: secondoption choice\n"
1651 "", /* tp_doc */
1652 0, /* tp_traverse */
1653 0, /* tp_clear */
1654 0, /* tp_richcompare */
1655 0, /* tp_weaklistoffset */
1656 0, /* tp_iter */
1657 0, /* tp_iternext */
1658 0, /* tp_methods */
1659 0, /* tp_members */
1660 Constraint_getseters, /* tp_getset */
1661 0, /* tp_base */
1662 0, /* tp_dict */
1663 0, /* tp_descr_get */
1664 0, /* tp_descr_set */
1665 0, /* tp_dictoffset */
1666 (initproc)Constraint_init, /* tp_init */
1667 0, /* tp_alloc */
1668 Constraint_new, /* tp_new */
1669 };
1670
1671 ///////////////
1672 // Attribute //
1673 ///////////////
1674
1675 static PyObject *
Attribute_new(PyTypeObject * type,PyObject * args,PyObject * kwds)1676 Attribute_new (PyTypeObject *type, PyObject *args, PyObject *kwds)
1677 {
1678 Attribute *self;
1679 self = (Attribute *) type->tp_alloc (type, 0);
1680 return (PyObject *) self;
1681 }
1682
1683 static int
Attribute_init(Attribute * self,PyObject * args,PyObject * kwds)1684 Attribute_init (Attribute *self, PyObject *args, PyObject *kwds)
1685 {
1686 self->attribute = NULL;
1687 return 0;
1688 }
1689
1690 static void
Attribute_dealloc(Attribute * self)1691 Attribute_dealloc (Attribute *self)
1692 {
1693 Py_XDECREF (self->ppd);
1694 ((PyObject *)self)->ob_type->tp_free ((PyObject *) self);
1695 }
1696
1697 static PyObject *
Attribute_repr(Attribute * self)1698 Attribute_repr (Attribute *self)
1699 {
1700 ppd_attr_t *attribute = self->attribute;
1701 if (!attribute)
1702 return PyUnicode_FromString ("<cups.Attribute>");
1703
1704 char buffer[256];
1705 snprintf (buffer, 256, "<cups.Attribute *%s%s%s>",
1706 attribute->name,
1707 attribute->spec[0] != '\0' ? " ": "",
1708 attribute->spec);
1709 return PyUnicode_FromString (buffer);
1710 }
1711
1712 ///////////////
1713 // Attribute // ATTRIBUTES
1714 ///////////////
1715
1716 static PyObject *
Attribute_getName(Attribute * self,void * closure)1717 Attribute_getName (Attribute *self, void *closure)
1718 {
1719 if (!self->attribute) {
1720 Py_RETURN_NONE;
1721 }
1722
1723 return make_PyUnicode_from_ppd_string (self->ppd, self->attribute->name);
1724 }
1725
1726 static PyObject *
Attribute_getSpec(Attribute * self,void * closure)1727 Attribute_getSpec (Attribute *self, void *closure)
1728 {
1729 if (!self->attribute) {
1730 Py_RETURN_NONE;
1731 }
1732
1733 return make_PyUnicode_from_ppd_string (self->ppd, self->attribute->spec);
1734 }
1735
1736 static PyObject *
Attribute_getText(Attribute * self,void * closure)1737 Attribute_getText (Attribute *self, void *closure)
1738 {
1739 if (!self->attribute) {
1740 Py_RETURN_NONE;
1741 }
1742
1743 return make_PyUnicode_from_ppd_string (self->ppd, self->attribute->text);
1744 }
1745
1746 static PyObject *
Attribute_getValue(Attribute * self,void * closure)1747 Attribute_getValue (Attribute *self, void *closure)
1748 {
1749 if (!self->attribute) {
1750 Py_RETURN_NONE;
1751 }
1752
1753 return make_PyUnicode_from_ppd_string (self->ppd, self->attribute->value);
1754 }
1755
1756 PyGetSetDef Attribute_getseters[] =
1757 {
1758 { "name",
1759 (getter) Attribute_getName, (setter) NULL,
1760 "name", NULL },
1761
1762 { "spec",
1763 (getter) Attribute_getSpec, (setter) NULL,
1764 "spec", NULL },
1765
1766 { "text",
1767 (getter) Attribute_getText, (setter) NULL,
1768 "text", NULL },
1769
1770 { "value",
1771 (getter) Attribute_getValue, (setter) NULL,
1772 "value", NULL },
1773
1774 { NULL }
1775 };
1776
1777 PyTypeObject cups_AttributeType =
1778 {
1779 PyVarObject_HEAD_INIT(NULL, 0)
1780 "cups.Attribute", /*tp_name*/
1781 sizeof(Attribute), /*tp_basicsize*/
1782 0, /*tp_itemsize*/
1783 (destructor)Attribute_dealloc, /*tp_dealloc*/
1784 0, /*tp_print*/
1785 0, /*tp_getattr*/
1786 0, /*tp_setattr*/
1787 0, /*tp_compare*/
1788 (reprfunc)Attribute_repr, /*tp_repr*/
1789 0, /*tp_as_number*/
1790 0, /*tp_as_sequence*/
1791 0, /*tp_as_mapping*/
1792 0, /*tp_hash */
1793 0, /*tp_call*/
1794 0, /*tp_str*/
1795 0, /*tp_getattro*/
1796 0, /*tp_setattro*/
1797 0, /*tp_as_buffer*/
1798 Py_TPFLAGS_DEFAULT, /*tp_flags*/
1799 "PPD attribute\n"
1800 "=============\n\n"
1801 " A PPD attribute.\n\n"
1802 "@type name: string\n"
1803 "@ivar name: attribute name\n"
1804 "@type spec: string\n"
1805 "@ivar spec: specifier string (if any)\n"
1806 "@type text: string\n"
1807 "@ivar text: human-readable text (if any)\n"
1808 "@type value: string\n"
1809 "@ivar value: attribute value\n"
1810 "", /* tp_doc */
1811 0, /* tp_traverse */
1812 0, /* tp_clear */
1813 0, /* tp_richcompare */
1814 0, /* tp_weaklistoffset */
1815 0, /* tp_iter */
1816 0, /* tp_iternext */
1817 0, /* tp_methods */
1818 0, /* tp_members */
1819 Attribute_getseters, /* tp_getset */
1820 0, /* tp_base */
1821 0, /* tp_dict */
1822 0, /* tp_descr_get */
1823 0, /* tp_descr_set */
1824 0, /* tp_dictoffset */
1825 (initproc)Attribute_init, /* tp_init */
1826 0, /* tp_alloc */
1827 Attribute_new, /* tp_new */
1828 };
1829