Coverage Report

Created: 2026-09-01 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cups/cups/encode.c
Line
Count
Source
1
/*
2
 * Option encoding routines for CUPS.
3
 *
4
 * Copyright © 2020-2026 by OpenPrinting.
5
 * Copyright © 2007-2019 by Apple Inc.
6
 * Copyright © 1997-2007 by Easy Software Products.
7
 *
8
 * Licensed under Apache License v2.0.  See the file "LICENSE" for more
9
 * information.
10
 */
11
12
#include "cups-private.h"
13
#include "debug-internal.h"
14
15
16
/*
17
 * Local list of option names, the value tags they should use, and the list of
18
 * supported operations...
19
 *
20
 * **** THIS LIST MUST BE SORTED BY ATTRIBUTE NAME ****
21
 */
22
23
static const ipp_op_t ipp_job_creation[] =
24
{
25
  IPP_OP_PRINT_JOB,
26
  IPP_OP_PRINT_URI,
27
  IPP_OP_VALIDATE_JOB,
28
  IPP_OP_CREATE_JOB,
29
  IPP_OP_HOLD_JOB,
30
  IPP_OP_SET_JOB_ATTRIBUTES,
31
  IPP_OP_CUPS_NONE
32
};
33
34
static const ipp_op_t ipp_doc_creation[] =
35
{
36
  IPP_OP_PRINT_JOB,
37
  IPP_OP_PRINT_URI,
38
  IPP_OP_SEND_DOCUMENT,
39
  IPP_OP_SEND_URI,
40
  IPP_OP_SET_JOB_ATTRIBUTES,
41
  IPP_OP_SET_DOCUMENT_ATTRIBUTES,
42
  IPP_OP_CUPS_NONE
43
};
44
45
static const ipp_op_t ipp_sub_creation[] =
46
{
47
  IPP_OP_PRINT_JOB,
48
  IPP_OP_PRINT_URI,
49
  IPP_OP_CREATE_JOB,
50
  IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS,
51
  IPP_OP_CREATE_JOB_SUBSCRIPTIONS,
52
  IPP_OP_CUPS_NONE
53
};
54
55
static const ipp_op_t ipp_all_print[] =
56
{
57
  IPP_OP_PRINT_JOB,
58
  IPP_OP_PRINT_URI,
59
  IPP_OP_VALIDATE_JOB,
60
  IPP_OP_CREATE_JOB,
61
  IPP_OP_SEND_DOCUMENT,
62
  IPP_OP_SEND_URI,
63
  IPP_OP_CUPS_NONE
64
};
65
66
static const ipp_op_t ipp_set_printer[] =
67
{
68
  IPP_OP_SET_PRINTER_ATTRIBUTES,
69
  IPP_OP_CUPS_ADD_MODIFY_PRINTER,
70
  IPP_OP_CUPS_ADD_MODIFY_CLASS,
71
  IPP_OP_CUPS_NONE
72
};
73
74
static const ipp_op_t cups_schemes[] =
75
{
76
  IPP_OP_CUPS_GET_DEVICES,
77
  IPP_OP_CUPS_GET_PPDS,
78
  IPP_OP_CUPS_NONE
79
};
80
81
static const ipp_op_t cups_get_ppds[] =
82
{
83
  IPP_OP_CUPS_GET_PPDS,
84
  IPP_OP_CUPS_NONE
85
};
86
87
static const ipp_op_t cups_ppd_name[] =
88
{
89
  IPP_OP_CUPS_ADD_MODIFY_PRINTER,
90
  IPP_OP_CUPS_GET_PPD,
91
  IPP_OP_CUPS_NONE
92
};
93
94
static const _ipp_option_t ipp_options[] =
95
{
96
  { 1, "auth-info",   IPP_TAG_TEXT,   IPP_TAG_JOB },
97
  { 1, "auth-info-default", IPP_TAG_TEXT,   IPP_TAG_PRINTER },
98
  { 1, "auth-info-required",  IPP_TAG_KEYWORD,  IPP_TAG_PRINTER },
99
  { 0, "blackplot",   IPP_TAG_BOOLEAN,  IPP_TAG_JOB },
100
  { 0, "blackplot-default", IPP_TAG_BOOLEAN,  IPP_TAG_PRINTER },
101
  { 0, "brightness",    IPP_TAG_INTEGER,  IPP_TAG_JOB },
102
  { 0, "brightness-default",  IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
103
  { 0, "columns",   IPP_TAG_INTEGER,  IPP_TAG_JOB },
104
  { 0, "columns-default", IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
105
  { 0, "compression",   IPP_TAG_KEYWORD,  IPP_TAG_OPERATION,
106
              IPP_TAG_ZERO,
107
              ipp_doc_creation },
108
  { 0, "copies",    IPP_TAG_INTEGER,  IPP_TAG_JOB,
109
              IPP_TAG_DOCUMENT },
110
  { 0, "copies-default",  IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
111
  { 0, "date-time-at-completed",IPP_TAG_DATE,   IPP_TAG_ZERO }, /* never send as option */
112
  { 0, "date-time-at-creation", IPP_TAG_DATE,   IPP_TAG_ZERO }, /* never send as option */
113
  { 0, "date-time-at-processing",IPP_TAG_DATE,    IPP_TAG_ZERO }, /* never send as option */
114
  { 0, "device-uri",    IPP_TAG_URI,    IPP_TAG_PRINTER },
115
  { 1, "document-copies", IPP_TAG_RANGE,    IPP_TAG_JOB,
116
              IPP_TAG_DOCUMENT,
117
              ipp_doc_creation },
118
  { 0, "document-format", IPP_TAG_MIMETYPE, IPP_TAG_OPERATION,
119
              IPP_TAG_ZERO,
120
              ipp_doc_creation },
121
  { 0, "document-format-default", IPP_TAG_MIMETYPE, IPP_TAG_PRINTER },
122
  { 1, "document-numbers",  IPP_TAG_RANGE,    IPP_TAG_JOB,
123
              IPP_TAG_DOCUMENT,
124
              ipp_all_print },
125
  { 1, "exclude-schemes", IPP_TAG_NAME,   IPP_TAG_OPERATION,
126
              IPP_TAG_ZERO,
127
              cups_schemes },
128
  { 1, "finishings",    IPP_TAG_ENUM,   IPP_TAG_JOB,
129
              IPP_TAG_DOCUMENT },
130
  { 1, "finishings-col",  IPP_TAG_BEGIN_COLLECTION, IPP_TAG_JOB,
131
              IPP_TAG_DOCUMENT },
132
  { 1, "finishings-col-default", IPP_TAG_BEGIN_COLLECTION, IPP_TAG_PRINTER },
133
  { 1, "finishings-default",  IPP_TAG_ENUM,   IPP_TAG_PRINTER },
134
  { 0, "fit-to-page",   IPP_TAG_BOOLEAN,  IPP_TAG_JOB,
135
              IPP_TAG_DOCUMENT },
136
  { 0, "fit-to-page-default", IPP_TAG_BOOLEAN,  IPP_TAG_PRINTER },
137
  { 0, "fitplot",   IPP_TAG_BOOLEAN,  IPP_TAG_JOB },
138
  { 0, "fitplot-default", IPP_TAG_BOOLEAN,  IPP_TAG_PRINTER },
139
  { 0, "gamma",     IPP_TAG_INTEGER,  IPP_TAG_JOB },
140
  { 0, "gamma-default",   IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
141
  { 0, "hue",     IPP_TAG_INTEGER,  IPP_TAG_JOB },
142
  { 0, "hue-default",   IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
143
  { 1, "include-schemes", IPP_TAG_NAME,   IPP_TAG_OPERATION,
144
              IPP_TAG_ZERO,
145
              cups_schemes },
146
  { 0, "ipp-attribute-fidelity", IPP_TAG_BOOLEAN, IPP_TAG_OPERATION },
147
  { 0, "job-account-id",        IPP_TAG_NAME,           IPP_TAG_JOB },
148
  { 0, "job-account-id-default",IPP_TAG_NAME,           IPP_TAG_PRINTER },
149
  { 0, "job-accounting-user-id", IPP_TAG_NAME,          IPP_TAG_JOB },
150
  { 0, "job-accounting-user-id-default", IPP_TAG_NAME,  IPP_TAG_PRINTER },
151
  { 0, "job-authorization-uri", IPP_TAG_URI,    IPP_TAG_OPERATION },
152
  { 0, "job-cancel-after",  IPP_TAG_INTEGER,  IPP_TAG_JOB },
153
  { 0, "job-cancel-after-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
154
  { 0, "job-hold-until",  IPP_TAG_KEYWORD,  IPP_TAG_JOB },
155
  { 0, "job-hold-until-default", IPP_TAG_KEYWORD, IPP_TAG_PRINTER },
156
  { 0, "job-id",    IPP_TAG_INTEGER,  IPP_TAG_ZERO }, /* never send as option */
157
  { 0, "job-impressions", IPP_TAG_INTEGER,  IPP_TAG_OPERATION },
158
  { 0, "job-impressions-completed", IPP_TAG_INTEGER,  IPP_TAG_ZERO }, /* never send as option */
159
  { 0, "job-k-limit",   IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
160
  { 0, "job-k-octets",    IPP_TAG_INTEGER,  IPP_TAG_OPERATION },
161
  { 0, "job-k-octets-completed",IPP_TAG_INTEGER,  IPP_TAG_ZERO }, /* never send as option */
162
  { 0, "job-media-sheets",  IPP_TAG_INTEGER,  IPP_TAG_OPERATION },
163
  { 0, "job-media-sheets-completed", IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */
164
  { 0, "job-name",    IPP_TAG_NAME,   IPP_TAG_OPERATION,
165
              IPP_TAG_JOB },
166
  { 0, "job-page-limit",  IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
167
  { 0, "job-pages",   IPP_TAG_INTEGER,  IPP_TAG_OPERATION },
168
  { 0, "job-pages-completed", IPP_TAG_INTEGER,  IPP_TAG_ZERO }, /* never send as option */
169
  { 0, "job-password",          IPP_TAG_STRING,         IPP_TAG_OPERATION,
170
              IPP_TAG_ZERO,
171
              ipp_job_creation },
172
  { 0, "job-password-encryption", IPP_TAG_KEYWORD,      IPP_TAG_OPERATION,
173
              IPP_TAG_ZERO,
174
              ipp_job_creation },
175
  { 0, "job-priority",    IPP_TAG_INTEGER,  IPP_TAG_JOB },
176
  { 0, "job-priority-default",  IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
177
  { 0, "job-quota-period",  IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
178
  { 1, "job-sheets",    IPP_TAG_NAME,   IPP_TAG_JOB },
179
  { 0, "job-sheets-col",  IPP_TAG_BEGIN_COLLECTION, IPP_TAG_JOB },
180
  { 0, "job-sheets-col-default",IPP_TAG_BEGIN_COLLECTION, IPP_TAG_PRINTER },
181
  { 1, "job-sheets-default",  IPP_TAG_NAME,   IPP_TAG_PRINTER },
182
  { 0, "job-state",   IPP_TAG_ENUM,   IPP_TAG_ZERO }, /* never send as option */
183
  { 0, "job-state-message", IPP_TAG_TEXT,   IPP_TAG_ZERO }, /* never send as option */
184
  { 0, "job-state-reasons", IPP_TAG_KEYWORD,  IPP_TAG_ZERO }, /* never send as option */
185
  { 0, "job-uuid",    IPP_TAG_URI,    IPP_TAG_JOB },
186
  { 0, "landscape",   IPP_TAG_BOOLEAN,  IPP_TAG_JOB },
187
  { 1, "marker-change-time",  IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
188
  { 1, "marker-colors",   IPP_TAG_NAME,   IPP_TAG_PRINTER },
189
  { 1, "marker-high-levels",  IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
190
  { 1, "marker-levels",   IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
191
  { 1, "marker-low-levels", IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
192
  { 0, "marker-message",  IPP_TAG_TEXT,   IPP_TAG_PRINTER },
193
  { 1, "marker-names",    IPP_TAG_NAME,   IPP_TAG_PRINTER },
194
  { 1, "marker-types",    IPP_TAG_KEYWORD,  IPP_TAG_PRINTER },
195
  { 1, "media",     IPP_TAG_KEYWORD,  IPP_TAG_JOB,
196
              IPP_TAG_DOCUMENT },
197
  { 0, "media-bottom-margin", IPP_TAG_INTEGER,  IPP_TAG_JOB,
198
              IPP_TAG_DOCUMENT },
199
  { 0, "media-col",   IPP_TAG_BEGIN_COLLECTION, IPP_TAG_JOB,
200
              IPP_TAG_DOCUMENT },
201
  { 0, "media-col-default", IPP_TAG_BEGIN_COLLECTION, IPP_TAG_PRINTER },
202
  { 0, "media-color",   IPP_TAG_KEYWORD,  IPP_TAG_JOB,
203
              IPP_TAG_DOCUMENT },
204
  { 1, "media-default",   IPP_TAG_KEYWORD,  IPP_TAG_PRINTER },
205
  { 0, "media-key",   IPP_TAG_KEYWORD,  IPP_TAG_JOB,
206
              IPP_TAG_DOCUMENT },
207
  { 0, "media-left-margin", IPP_TAG_INTEGER,  IPP_TAG_JOB,
208
              IPP_TAG_DOCUMENT },
209
  { 0, "media-right-margin",  IPP_TAG_INTEGER,  IPP_TAG_JOB,
210
              IPP_TAG_DOCUMENT },
211
  { 0, "media-size",    IPP_TAG_BEGIN_COLLECTION, IPP_TAG_JOB,
212
              IPP_TAG_DOCUMENT },
213
  { 0, "media-size-name", IPP_TAG_KEYWORD,  IPP_TAG_JOB,
214
              IPP_TAG_DOCUMENT },
215
  { 0, "media-source",    IPP_TAG_KEYWORD,  IPP_TAG_JOB,
216
              IPP_TAG_DOCUMENT },
217
  { 0, "media-top-margin",  IPP_TAG_INTEGER,  IPP_TAG_JOB,
218
              IPP_TAG_DOCUMENT },
219
  { 0, "media-type",    IPP_TAG_KEYWORD,  IPP_TAG_JOB,
220
              IPP_TAG_DOCUMENT },
221
  { 0, "mirror",    IPP_TAG_BOOLEAN,  IPP_TAG_JOB },
222
  { 0, "mirror-default",  IPP_TAG_BOOLEAN,  IPP_TAG_PRINTER },
223
  { 0, "multiple-document-handling", IPP_TAG_KEYWORD, IPP_TAG_JOB,
224
              IPP_TAG_DOCUMENT },
225
  { 0, "multiple-document-handling-default", IPP_TAG_KEYWORD, IPP_TAG_PRINTER },
226
  { 0, "natural-scaling", IPP_TAG_INTEGER,  IPP_TAG_JOB },
227
  { 0, "natural-scaling-default", IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
228
  { 0, "notify-charset",  IPP_TAG_CHARSET,  IPP_TAG_SUBSCRIPTION },
229
  { 1, "notify-events",   IPP_TAG_KEYWORD,  IPP_TAG_SUBSCRIPTION },
230
  { 1, "notify-events-default", IPP_TAG_KEYWORD,  IPP_TAG_PRINTER },
231
  { 0, "notify-lease-duration", IPP_TAG_INTEGER,  IPP_TAG_SUBSCRIPTION },
232
  { 0, "notify-lease-duration-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
233
  { 0, "notify-natural-language", IPP_TAG_LANGUAGE, IPP_TAG_SUBSCRIPTION },
234
  { 0, "notify-pull-method",  IPP_TAG_KEYWORD,  IPP_TAG_SUBSCRIPTION },
235
  { 0, "notify-recipient-uri",  IPP_TAG_URI,    IPP_TAG_SUBSCRIPTION },
236
  { 0, "notify-time-interval",  IPP_TAG_INTEGER,  IPP_TAG_SUBSCRIPTION },
237
  { 0, "notify-user-data",  IPP_TAG_STRING,   IPP_TAG_SUBSCRIPTION },
238
  { 0, "number-up",   IPP_TAG_INTEGER,  IPP_TAG_JOB,
239
              IPP_TAG_DOCUMENT },
240
  { 0, "number-up-default", IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
241
  { 0, "number-up-layout",  IPP_TAG_KEYWORD,  IPP_TAG_JOB,
242
              IPP_TAG_DOCUMENT },
243
  { 0, "number-up-layout-default", IPP_TAG_KEYWORD, IPP_TAG_PRINTER },
244
  { 0, "orientation-requested", IPP_TAG_ENUM,   IPP_TAG_JOB,
245
              IPP_TAG_DOCUMENT },
246
  { 0, "orientation-requested-default", IPP_TAG_ENUM, IPP_TAG_PRINTER },
247
  { 0, "output-bin",    IPP_TAG_KEYWORD,  IPP_TAG_JOB,
248
              IPP_TAG_DOCUMENT },
249
  { 0, "output-bin-default",  IPP_TAG_KEYWORD,  IPP_TAG_PRINTER },
250
  { 1, "overrides",   IPP_TAG_BEGIN_COLLECTION, IPP_TAG_JOB,
251
              IPP_TAG_DOCUMENT },
252
  { 0, "page-bottom",   IPP_TAG_INTEGER,  IPP_TAG_JOB },
253
  { 0, "page-bottom-default", IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
254
  { 0, "page-delivery",   IPP_TAG_KEYWORD,  IPP_TAG_JOB,
255
              IPP_TAG_DOCUMENT },
256
  { 0, "page-delivery-default", IPP_TAG_KEYWORD,  IPP_TAG_PRINTER },
257
  { 0, "page-left",   IPP_TAG_INTEGER,  IPP_TAG_JOB },
258
  { 0, "page-left-default", IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
259
  { 1, "page-ranges",   IPP_TAG_RANGE,    IPP_TAG_JOB,
260
              IPP_TAG_DOCUMENT },
261
  { 0, "page-right",    IPP_TAG_INTEGER,  IPP_TAG_JOB },
262
  { 0, "page-right-default",  IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
263
  { 0, "page-top",    IPP_TAG_INTEGER,  IPP_TAG_JOB },
264
  { 0, "page-top-default",  IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
265
  { 1, "pages",     IPP_TAG_RANGE,    IPP_TAG_JOB,
266
              IPP_TAG_DOCUMENT },
267
  { 0, "penwidth",    IPP_TAG_INTEGER,  IPP_TAG_JOB },
268
  { 0, "penwidth-default",  IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
269
  { 0, "port-monitor",    IPP_TAG_NAME,   IPP_TAG_PRINTER },
270
  { 0, "ppd-device-id",   IPP_TAG_TEXT,   IPP_TAG_OPERATION,
271
              IPP_TAG_ZERO,
272
              cups_get_ppds },
273
  { 0, "ppd-make",    IPP_TAG_TEXT,   IPP_TAG_OPERATION,
274
              IPP_TAG_ZERO,
275
              cups_get_ppds },
276
  { 0, "ppd-make-and-model",  IPP_TAG_TEXT,   IPP_TAG_OPERATION,
277
              IPP_TAG_ZERO,
278
              cups_get_ppds },
279
  { 0, "ppd-model-number",  IPP_TAG_INTEGER,  IPP_TAG_OPERATION,
280
              IPP_TAG_ZERO,
281
              cups_get_ppds },
282
  { 0, "ppd-name",    IPP_TAG_NAME,   IPP_TAG_OPERATION,
283
              IPP_TAG_ZERO,
284
              cups_ppd_name },
285
  { 0, "ppd-natural-language",  IPP_TAG_LANGUAGE, IPP_TAG_OPERATION,
286
              IPP_TAG_ZERO,
287
              cups_get_ppds },
288
  { 0, "ppd-product",   IPP_TAG_TEXT,   IPP_TAG_OPERATION,
289
              IPP_TAG_ZERO,
290
              cups_get_ppds },
291
  { 0, "ppd-psversion",   IPP_TAG_TEXT,   IPP_TAG_OPERATION,
292
              IPP_TAG_ZERO,
293
              cups_get_ppds },
294
  { 0, "ppd-type",    IPP_TAG_KEYWORD,  IPP_TAG_OPERATION,
295
              IPP_TAG_ZERO,
296
              cups_get_ppds },
297
  { 0, "ppi",     IPP_TAG_INTEGER,  IPP_TAG_JOB },
298
  { 0, "ppi-default",   IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
299
  { 0, "prettyprint",   IPP_TAG_BOOLEAN,  IPP_TAG_JOB },
300
  { 0, "prettyprint-default", IPP_TAG_BOOLEAN,  IPP_TAG_PRINTER },
301
  { 0, "print-as-raster", IPP_TAG_BOOLEAN,  IPP_TAG_JOB },
302
  { 0, "print-as-raster-default", IPP_TAG_BOOLEAN,  IPP_TAG_PRINTER },
303
  { 0, "print-color-mode",  IPP_TAG_KEYWORD,  IPP_TAG_JOB,
304
              IPP_TAG_DOCUMENT },
305
  { 0, "print-color-mode-default", IPP_TAG_KEYWORD, IPP_TAG_PRINTER },
306
  { 0, "print-content-optimize", IPP_TAG_KEYWORD, IPP_TAG_JOB,
307
              IPP_TAG_DOCUMENT },
308
  { 0, "print-content-optimize-default", IPP_TAG_KEYWORD, IPP_TAG_PRINTER },
309
  { 0, "print-quality",   IPP_TAG_ENUM,   IPP_TAG_JOB,
310
              IPP_TAG_DOCUMENT },
311
  { 0, "print-quality-default", IPP_TAG_ENUM,   IPP_TAG_PRINTER },
312
  { 0, "print-rendering-intent", IPP_TAG_KEYWORD, IPP_TAG_JOB,
313
              IPP_TAG_DOCUMENT },
314
  { 0, "print-rendering-intent-default", IPP_TAG_KEYWORD, IPP_TAG_PRINTER },
315
  { 0, "print-scaling",   IPP_TAG_KEYWORD,  IPP_TAG_JOB,
316
              IPP_TAG_DOCUMENT },
317
  { 0, "print-scaling-default", IPP_TAG_KEYWORD,  IPP_TAG_PRINTER },
318
  { 1, "printer-alert",   IPP_TAG_STRING,   IPP_TAG_PRINTER },
319
  { 1, "printer-alert-description", IPP_TAG_TEXT, IPP_TAG_PRINTER },
320
  { 1, "printer-commands",  IPP_TAG_KEYWORD,  IPP_TAG_PRINTER },
321
  { 0, "printer-error-policy",  IPP_TAG_NAME,   IPP_TAG_PRINTER },
322
  { 1, "printer-finisher",  IPP_TAG_STRING,   IPP_TAG_PRINTER },
323
  { 1, "printer-finisher-description", IPP_TAG_TEXT,  IPP_TAG_PRINTER },
324
  { 1, "printer-finisher-supplies", IPP_TAG_STRING, IPP_TAG_PRINTER },
325
  { 1, "printer-finisher-supplies-description", IPP_TAG_TEXT, IPP_TAG_PRINTER },
326
  { 0, "printer-geo-location",  IPP_TAG_URI,    IPP_TAG_PRINTER },
327
  { 0, "printer-info",    IPP_TAG_TEXT,   IPP_TAG_PRINTER },
328
  { 1, "printer-input-tray",  IPP_TAG_STRING,   IPP_TAG_PRINTER },
329
  { 0, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN,  IPP_TAG_PRINTER },
330
  { 0, "printer-is-shared", IPP_TAG_BOOLEAN,  IPP_TAG_PRINTER },
331
  { 0, "printer-is-temporary",  IPP_TAG_BOOLEAN,  IPP_TAG_PRINTER },
332
  { 0, "printer-location",  IPP_TAG_TEXT,   IPP_TAG_PRINTER },
333
  { 0, "printer-make-and-model", IPP_TAG_TEXT,    IPP_TAG_PRINTER },
334
  { 0, "printer-more-info", IPP_TAG_URI,    IPP_TAG_PRINTER },
335
  { 0, "printer-op-policy", IPP_TAG_NAME,   IPP_TAG_PRINTER },
336
  { 1, "printer-output-tray", IPP_TAG_STRING,   IPP_TAG_PRINTER },
337
  { 0, "printer-resolution",  IPP_TAG_RESOLUTION, IPP_TAG_JOB,
338
              IPP_TAG_DOCUMENT },
339
  { 0, "printer-resolution-default", IPP_TAG_RESOLUTION, IPP_TAG_PRINTER },
340
  { 0, "printer-state",   IPP_TAG_ENUM,   IPP_TAG_PRINTER },
341
  { 0, "printer-state-change-time", IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
342
  { 1, "printer-state-reasons", IPP_TAG_KEYWORD,  IPP_TAG_PRINTER },
343
  { 1, "printer-supply",  IPP_TAG_STRING,   IPP_TAG_PRINTER },
344
  { 1, "printer-supply-description", IPP_TAG_TEXT,  IPP_TAG_PRINTER },
345
  { 0, "printer-type",    IPP_TAG_ENUM,   IPP_TAG_PRINTER },
346
  { 0, "printer-uri",   IPP_TAG_URI,    IPP_TAG_OPERATION },
347
  { 1, "printer-uri-supported", IPP_TAG_URI,    IPP_TAG_PRINTER },
348
  { 0, "queued-job-count",  IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
349
  { 0, "raw",     IPP_TAG_MIMETYPE, IPP_TAG_OPERATION },
350
  { 1, "requested-attributes",  IPP_TAG_NAME,   IPP_TAG_OPERATION },
351
  { 1, "requesting-user-name-allowed", IPP_TAG_NAME,  IPP_TAG_PRINTER },
352
  { 1, "requesting-user-name-denied", IPP_TAG_NAME, IPP_TAG_PRINTER },
353
  { 0, "resolution",    IPP_TAG_RESOLUTION, IPP_TAG_JOB },
354
  { 0, "resolution-default",  IPP_TAG_RESOLUTION, IPP_TAG_PRINTER },
355
  { 0, "saturation",    IPP_TAG_INTEGER,  IPP_TAG_JOB },
356
  { 0, "saturation-default",  IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
357
  { 0, "scaling",   IPP_TAG_INTEGER,  IPP_TAG_JOB },
358
  { 0, "scaling-default", IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
359
  { 0, "sides",     IPP_TAG_KEYWORD,  IPP_TAG_JOB,
360
              IPP_TAG_DOCUMENT },
361
  { 0, "sides-default",   IPP_TAG_KEYWORD,  IPP_TAG_PRINTER },
362
  { 0, "time-at-completed", IPP_TAG_INTEGER,  IPP_TAG_ZERO }, /* never send as option */
363
  { 0, "time-at-creation",  IPP_TAG_INTEGER,  IPP_TAG_ZERO }, /* never send as option */
364
  { 0, "time-at-processing",  IPP_TAG_INTEGER,  IPP_TAG_ZERO }, /* never send as option */
365
  { 0, "wrap",      IPP_TAG_BOOLEAN,  IPP_TAG_JOB },
366
  { 0, "wrap-default",    IPP_TAG_BOOLEAN,  IPP_TAG_PRINTER },
367
  { 0, "x-dimension",   IPP_TAG_INTEGER,  IPP_TAG_JOB,
368
              IPP_TAG_DOCUMENT },
369
  { 0, "y-dimension",   IPP_TAG_INTEGER,  IPP_TAG_JOB,
370
              IPP_TAG_DOCUMENT }
371
};
372
373
374
/*
375
 * Local functions...
376
 */
377
378
static int  compare_ipp_options(_ipp_option_t *a, _ipp_option_t *b);
379
static void encode_options(ipp_t *ipp, int num_options, cups_option_t *options, ipp_tag_t group_tag, int depth);
380
381
382
/*
383
 * '_cupsEncodeOption()' - Encode a single option as an IPP attribute.
384
 */
385
386
ipp_attribute_t *     /* O - New attribute or @code NULL@ on error */
387
_cupsEncodeOption(
388
    ipp_t         *ipp,     /* I - IPP request/response/collection */
389
    ipp_tag_t     group_tag,    /* I - Group tag */
390
    _ipp_option_t *map,     /* I - Option mapping, if any */
391
    const char    *name,    /* I - Attribute name */
392
    const char    *value,   /* I - Value */
393
    int           depth)    /* I - Depth of values */
394
0
{
395
0
  int     i,    /* Looping var */
396
0
      count;    /* Number of values */
397
0
  char      *s,   /* Pointer into option value */
398
0
      *val,   /* Pointer to option value */
399
0
      *copy,    /* Copy of option value */
400
0
      *sep,   /* Option separator */
401
0
      quote;    /* Quote character */
402
0
  ipp_attribute_t *attr;    /* IPP attribute */
403
0
  ipp_tag_t   value_tag;  /* IPP value tag */
404
0
  ipp_t     *collection;  /* Collection value */
405
0
  int     num_cols; /* Number of collection values */
406
0
  cups_option_t   *cols;    /* Collection values */
407
408
409
0
  DEBUG_printf("_cupsEncodeOption(ipp=%p(%s), group=%s, map=%p, name=\"%s\", value=\"%s\")", (void *)ipp, ipp ? ippOpString(ippGetOperation(ipp)) : "", ippTagString(group_tag), (void *)map, name, value);
410
411
 /*
412
  * Figure out the attribute syntax for encoding...
413
  */
414
415
0
  if (!map)
416
0
    map = _ippFindOption(name);
417
418
0
  if (map)
419
0
    value_tag = map->value_tag;
420
0
  else if (!_cups_strcasecmp(value, "true") || !_cups_strcasecmp(value, "false"))
421
0
    value_tag = IPP_TAG_BOOLEAN;
422
0
  else if (value[0] == '{')
423
0
    value_tag = IPP_TAG_BEGIN_COLLECTION;
424
0
  else
425
0
    value_tag = IPP_TAG_NAME;
426
427
 /*
428
  * Count the number of values...
429
  */
430
431
0
  if (map && map->multivalue)
432
0
  {
433
0
    for (count = 1, sep = (char *)value, quote = 0; *sep; sep ++)
434
0
    {
435
0
      if (*sep == quote)
436
0
  quote = 0;
437
0
      else if (!quote && (*sep == '\'' || *sep == '\"'))
438
0
      {
439
       /*
440
  * Skip quoted option value...
441
  */
442
443
0
  quote = *sep;
444
0
      }
445
0
      else if (*sep == ',' && !quote)
446
0
  count ++;
447
0
      else if (*sep == '\\' && sep[1])
448
0
  sep ++;
449
0
    }
450
0
  }
451
0
  else
452
0
    count = 1;
453
454
0
  DEBUG_printf("2_cupsEncodeOption: value_tag=%s, count=%d", ippTagString(value_tag), count);
455
456
 /*
457
  * Allocate memory for the attribute values...
458
  */
459
460
0
  if ((attr = ippAddStrings(ipp, group_tag, value_tag, name, count, NULL, NULL)) == NULL)
461
0
  {
462
   /*
463
    * Ran out of memory!
464
    */
465
466
0
    DEBUG_puts("1_cupsEncodeOption: Ran out of memory for attributes.");
467
0
    return (NULL);
468
0
  }
469
470
0
  if (count > 1)
471
0
  {
472
   /*
473
    * Make a copy of the value we can fiddle with...
474
    */
475
476
0
    if ((copy = strdup(value)) == NULL)
477
0
    {
478
     /*
479
      * Ran out of memory!
480
      */
481
482
0
      DEBUG_puts("1_cupsEncodeOption: Ran out of memory for value copy.");
483
0
      ippDeleteAttribute(ipp, attr);
484
0
      return (NULL);
485
0
    }
486
487
0
    val = copy;
488
0
  }
489
0
  else
490
0
  {
491
   /*
492
    * Since we have a single value, use the value directly...
493
    */
494
495
0
    val  = (char *)value;
496
0
    copy = NULL;
497
0
  }
498
499
 /*
500
  * Scan the value string for values...
501
  */
502
503
0
  for (i = 0, sep = val; i < count; val = sep, i ++)
504
0
  {
505
   /*
506
    * Find the end of this value and mark it if needed...
507
    */
508
509
0
    if (count > 1)
510
0
    {
511
0
      for (quote = 0; *sep; sep ++)
512
0
      {
513
0
  if (*sep == quote)
514
0
  {
515
   /*
516
    * Finish quoted value...
517
    */
518
519
0
    quote = 0;
520
0
  }
521
0
  else if (!quote && (*sep == '\'' || *sep == '\"'))
522
0
  {
523
   /*
524
    * Handle quoted option value...
525
    */
526
527
0
    quote = *sep;
528
0
  }
529
0
  else if (*sep == ',')
530
0
    break;
531
0
  else if (*sep == '\\' && sep[1])
532
0
  {
533
   /*
534
    * Skip quoted character...
535
    */
536
537
0
    memmove(sep, sep + 1, strlen(sep));
538
0
  }
539
0
      }
540
541
0
      if (*sep == ',')
542
0
  *sep++ = '\0';
543
0
    }
544
545
   /*
546
    * Copy the option value(s) over as needed by the type...
547
    */
548
549
0
    switch (attr->value_tag)
550
0
    {
551
0
      case IPP_TAG_ENUM :
552
0
          if (isalpha(*val & 255))
553
0
          {
554
            // Map enum keyword to integer value...
555
0
            int enumvalue;    // Enumeration value
556
557
0
            if ((enumvalue = ippEnumValue(name, val)) > 0)
558
0
            {
559
0
              ippSetInteger(ipp, &attr, i, enumvalue);
560
0
      }
561
0
      else
562
0
      {
563
0
        ippDeleteAttribute(ipp, attr);
564
0
        free(copy);
565
0
        return (NULL);
566
0
      }
567
0
            break;
568
0
    }
569
570
0
      case IPP_TAG_INTEGER :
571
   /*
572
    * Integer/enumeration value...
573
    */
574
575
0
    ippSetInteger(ipp, &attr, i, (int)strtol(val, &s, 10));
576
0
    break;
577
578
0
      case IPP_TAG_BOOLEAN :
579
0
    if (!_cups_strcasecmp(val, "true") || !_cups_strcasecmp(val, "on") || !_cups_strcasecmp(val, "yes"))
580
0
    {
581
     /*
582
      * Boolean value - true...
583
      */
584
585
0
            ippSetBoolean(ipp, &attr, i, 1);
586
0
    }
587
0
    else
588
0
    {
589
     /*
590
      * Boolean value - false...
591
      */
592
593
0
            ippSetBoolean(ipp, &attr, i, 0);
594
0
    }
595
0
    break;
596
597
0
      case IPP_TAG_RANGE :
598
0
          {
599
     /*
600
      * Range...
601
      */
602
603
0
      int lower, upper;   /* Lower and upper ranges... */
604
605
0
      if (*val == '-')
606
0
      {
607
0
        lower = 1;
608
0
        s     = val;
609
0
      }
610
0
      else
611
0
        lower = (int)strtol(val, &s, 10);
612
613
0
      if (*s == '-')
614
0
      {
615
0
        if (s[1])
616
0
    upper = atoi(s + 1);
617
0
        else
618
0
    upper = 2147483647;
619
0
      }
620
0
      else
621
0
        upper = lower;
622
623
0
            ippSetRange(ipp, &attr, i, lower, upper);
624
0
    }
625
0
    break;
626
627
0
      case IPP_TAG_RESOLUTION :
628
0
          {
629
     /*
630
      * Resolution...
631
      */
632
0
      int   xres, yres; /* Resolution values */
633
0
      ipp_res_t units;    /* Resolution units */
634
635
0
      xres = (int)strtol(val, &s, 10);
636
637
0
      if (*s == 'x')
638
0
        yres = (int)strtol(s + 1, &s, 10);
639
0
      else
640
0
        yres = xres;
641
642
0
      if (!_cups_strcasecmp(s, "dpc") || !_cups_strcasecmp(s, "dpcm"))
643
0
        units = IPP_RES_PER_CM;
644
0
      else
645
0
        units = IPP_RES_PER_INCH;
646
647
0
      ippSetResolution(ipp, &attr, i, units, xres, yres);
648
0
          }
649
0
    break;
650
651
0
      case IPP_TAG_STRING :
652
   /*
653
    * octetString
654
    */
655
656
0
          ippSetOctetString(ipp, &attr, i, val, (int)strlen(val));
657
0
    break;
658
659
0
      case IPP_TAG_BEGIN_COLLECTION :
660
   /*
661
    * Collection value
662
    */
663
664
0
          if (depth >= _CUPS_MAX_OPTION_DEPTH)
665
0
          {
666
           /*
667
            * Don't allow "infinite" recursion of collection values...
668
            */
669
670
0
      if (copy)
671
0
        free(copy);
672
673
0
      ippDeleteAttribute(ipp, attr);
674
0
      return (NULL);
675
0
          }
676
677
0
    num_cols = cupsParseOptions(val, 0, &cols);
678
0
    if ((collection = ippNew()) == NULL)
679
0
    {
680
0
      cupsFreeOptions(num_cols, cols);
681
682
0
      if (copy)
683
0
        free(copy);
684
685
0
      ippDeleteAttribute(ipp, attr);
686
0
      return (NULL);
687
0
    }
688
689
0
    ippSetCollection(ipp, &attr, i, collection);
690
0
    encode_options(collection, num_cols, cols, IPP_TAG_JOB, depth + 1);
691
0
    cupsFreeOptions(num_cols, cols);
692
0
    ippDelete(collection);
693
0
    break;
694
695
0
      default :
696
0
    ippSetString(ipp, &attr, i, val);
697
0
    break;
698
0
    }
699
0
  }
700
701
0
  free(copy);
702
703
0
  return (attr);
704
0
}
705
706
707
/*
708
 * 'cupsEncodeOption()' - Encode a single option into an IPP attribute.
709
 *
710
 * @since CUPS 2.3@
711
 */
712
713
ipp_attribute_t *     /* O - New attribute or @code NULL@ on error */
714
cupsEncodeOption(ipp_t      *ipp, /* I - IPP request/response */
715
                 ipp_tag_t  group_tag,  /* I - Attribute group */
716
                 const char *name,  /* I - Option name */
717
                 const char *value) /* I - Option string value */
718
0
{
719
0
  return (_cupsEncodeOption(ipp, group_tag, _ippFindOption(name), name, value, /*depth*/0));
720
0
}
721
722
723
/*
724
 * 'cupsEncodeOptions()' - Encode printer options into IPP attributes.
725
 *
726
 * This function adds operation, job, and then subscription attributes,
727
 * in that order. Use the @link cupsEncodeOptions2@ function to add attributes
728
 * for a single group.
729
 */
730
731
void
732
cupsEncodeOptions(ipp_t         *ipp,   /* I - IPP request/response */
733
            int           num_options,  /* I - Number of options */
734
      cups_option_t *options) /* I - Options */
735
0
{
736
0
  DEBUG_printf("cupsEncodeOptions(%p, %d, %p)", (void *)ipp, num_options, (void *)options);
737
738
 /*
739
  * Add the options in the proper groups & order...
740
  */
741
742
0
  cupsEncodeOptions2(ipp, num_options, options, IPP_TAG_OPERATION);
743
0
  cupsEncodeOptions2(ipp, num_options, options, IPP_TAG_JOB);
744
0
  cupsEncodeOptions2(ipp, num_options, options, IPP_TAG_SUBSCRIPTION);
745
0
}
746
747
748
/*
749
 * 'cupsEncodeOptions2()' - Encode printer options into IPP attributes for a group.
750
 *
751
 * This function only adds attributes for a single group. Call this
752
 * function multiple times for each group, or use @link cupsEncodeOptions@
753
 * to add the standard groups.
754
 *
755
 * @since CUPS 1.2@
756
 */
757
758
void
759
cupsEncodeOptions2(
760
    ipp_t         *ipp,     /* I - IPP request/response */
761
    int           num_options,    /* I - Number of options */
762
    cups_option_t *options,   /* I - Options */
763
    ipp_tag_t     group_tag)    /* I - Group to encode */
764
0
{
765
0
  char      *val;   /* Pointer to option value */
766
0
  ipp_op_t    op;   /* Operation for this request */
767
768
769
0
  DEBUG_printf("cupsEncodeOptions2(ipp=%p(%s), num_options=%d, options=%p, group_tag=%x)", (void *)ipp, ipp ? ippOpString(ippGetOperation(ipp)) : "", num_options, (void *)options, group_tag);
770
771
 /*
772
  * Range check input...
773
  */
774
775
0
  if (!ipp || num_options < 1 || !options)
776
0
    return;
777
778
 /*
779
  * Do special handling for the document-format/raw options...
780
  */
781
782
0
  op = ippGetOperation(ipp);
783
784
0
  if (group_tag == IPP_TAG_OPERATION && (op == IPP_OP_PRINT_JOB || op == IPP_OP_PRINT_URI || op == IPP_OP_SEND_DOCUMENT || op == IPP_OP_SEND_URI) && !ippFindAttribute(ipp, "document-format", IPP_TAG_ZERO))
785
0
  {
786
   /*
787
    * Handle the document format stuff first...
788
    */
789
790
0
    if ((val = (char *)cupsGetOption("document-format", num_options, options)) != NULL)
791
0
      ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, val);
792
0
    else if (cupsGetOption("raw", num_options, options))
793
0
      ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, "application/vnd.cups-raw");
794
0
    else
795
0
      ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, "application/octet-stream");
796
0
  }
797
798
 /*
799
  * Then encode the options...
800
  */
801
802
0
  encode_options(ipp, num_options, options, group_tag, /*depth*/0);
803
0
}
804
805
806
#ifdef DEBUG
807
/*
808
 * '_ippCheckOptions()' - Validate that the option array is sorted properly.
809
 */
810
811
const char *        /* O - First out-of-order option or NULL */
812
_ippCheckOptions(void)
813
{
814
  int i;        /* Looping var */
815
816
817
  for (i = 0; i < (int)(sizeof(ipp_options) / sizeof(ipp_options[0]) - 1); i ++)
818
    if (strcmp(ipp_options[i].name, ipp_options[i + 1].name) >= 0)
819
      return (ipp_options[i + 1].name);
820
821
  return (NULL);
822
}
823
#endif /* DEBUG */
824
825
826
/*
827
 * '_ippFindOption()' - Find the attribute information for an option.
828
 */
829
830
_ipp_option_t *       /* O - Attribute information */
831
_ippFindOption(const char *name)  /* I - Option/attribute name */
832
0
{
833
0
  _ipp_option_t key;      /* Search key */
834
835
836
 /*
837
  * Lookup the proper value and group tags for this option...
838
  */
839
840
0
  key.name = name;
841
842
0
  return ((_ipp_option_t *)bsearch(&key, ipp_options,
843
0
                                   sizeof(ipp_options) / sizeof(ipp_options[0]),
844
0
           sizeof(ipp_options[0]),
845
0
           (int (*)(const void *, const void *))
846
0
               compare_ipp_options));
847
0
}
848
849
850
/*
851
 * 'compare_ipp_options()' - Compare two IPP options.
852
 */
853
854
static int        /* O - Result of comparison */
855
compare_ipp_options(_ipp_option_t *a, /* I - First option */
856
                    _ipp_option_t *b) /* I - Second option */
857
0
{
858
0
  return (strcmp(a->name, b->name));
859
0
}
860
861
862
/*
863
 * 'encode_options()' - Encode options to the specified depth.
864
 */
865
866
void
867
encode_options(
868
    ipp_t         *ipp,     /* I - IPP request/response */
869
    int           num_options,    /* I - Number of options */
870
    cups_option_t *options,   /* I - Options */
871
    ipp_tag_t     group_tag,    /* I - Group to encode */
872
    int           depth)    /* I - Depth of options/collections */
873
0
{
874
0
  int     i;    /* Looping var */
875
0
  cups_option_t   *option;  /* Current option */
876
0
  ipp_op_t    op = ippGetOperation(ipp);
877
          /* Operation for this request */
878
0
  const ipp_op_t  *ops;   /* List of allowed operations */
879
880
881
0
  DEBUG_printf("4encode_options(ipp=%p(%s), num_options=%d, options=%p, group_tag=%x, depth=%d)", (void *)ipp, ipp ? ippOpString(ippGetOperation(ipp)) : "", num_options, (void *)options, group_tag, depth);
882
883
 /*
884
  * Loop through the options...
885
  */
886
887
0
  for (i = num_options, option = options; i > 0; i --, option ++)
888
0
  {
889
0
    _ipp_option_t *match;   /* Matching attribute */
890
891
   /*
892
    * Skip document format options that are handled in cupsEncodeOptions2...
893
    */
894
895
0
    if (!_cups_strcasecmp(option->name, "raw") || !_cups_strcasecmp(option->name, "document-format") || !option->name[0])
896
0
      continue;
897
898
   /*
899
    * Figure out the proper value and group tags for this option...
900
    */
901
902
0
    if ((match = _ippFindOption(option->name)) != NULL)
903
0
    {
904
0
      if (match->group_tag != group_tag && match->alt_group_tag != group_tag)
905
0
        continue;
906
907
0
      if (match->operations)
908
0
        ops = match->operations;
909
0
      else if (group_tag == IPP_TAG_JOB)
910
0
        ops = ipp_job_creation;
911
0
      else if (group_tag == IPP_TAG_DOCUMENT)
912
0
        ops = ipp_doc_creation;
913
0
      else if (group_tag == IPP_TAG_SUBSCRIPTION)
914
0
        ops = ipp_sub_creation;
915
0
      else if (group_tag == IPP_TAG_PRINTER)
916
0
        ops = ipp_set_printer;
917
0
      else
918
0
      {
919
0
  DEBUG_printf("5encode_options: Skipping \"%s\".", option->name);
920
0
        continue;
921
0
      }
922
0
    }
923
0
    else
924
0
    {
925
0
      int namelen;    /* Length of name */
926
927
0
      namelen = (int)strlen(option->name);
928
929
0
      if (namelen < 10 || (strcmp(option->name + namelen - 8, "-default") && strcmp(option->name + namelen - 10, "-supported")))
930
0
      {
931
0
  if (group_tag != IPP_TAG_JOB && group_tag != IPP_TAG_DOCUMENT)
932
0
  {
933
0
    DEBUG_printf("5encode_options: Skipping \"%s\".", option->name);
934
0
          continue;
935
0
        }
936
0
      }
937
0
      else if (group_tag != IPP_TAG_PRINTER)
938
0
      {
939
0
  DEBUG_printf("5encode_options: Skipping \"%s\".", option->name);
940
0
        continue;
941
0
      }
942
943
0
      if (group_tag == IPP_TAG_JOB)
944
0
        ops = ipp_job_creation;
945
0
      else if (group_tag == IPP_TAG_DOCUMENT)
946
0
        ops = ipp_doc_creation;
947
0
      else
948
0
        ops = ipp_set_printer;
949
0
    }
950
951
   /*
952
    * Verify that we send this attribute for this operation...
953
    */
954
955
0
    while (*ops != IPP_OP_CUPS_NONE)
956
0
      if (op == *ops)
957
0
        break;
958
0
      else
959
0
        ops ++;
960
961
0
    if (*ops == IPP_OP_CUPS_NONE && op != IPP_OP_CUPS_NONE)
962
0
    {
963
0
      DEBUG_printf("5encode_options: Skipping \"%s\".", option->name);
964
0
      continue;
965
0
    }
966
967
0
    _cupsEncodeOption(ipp, group_tag, match, option->name, option->value, depth);
968
0
  }
969
0
}