]>
Commit | Line | Data |
---|---|---|
abacc52b MS |
1 | --- |
2 | title: CUPS Programming Manual | |
3 | author: Michael R Sweet | |
4 | copyright: Copyright (c) 2007-2017 by Apple Inc. All Rights Reserved. | |
5 | version: 2.2.4 | |
6 | ... | |
7 | ||
8 | # Introduction | |
9 | ||
10 | CUPS provides the "cups" library to talk to the different parts of CUPS and with | |
11 | Internet Printing Protocol (IPP) printers. The "cups" library functions are | |
12 | accessed by including the `<cups/cups.h>` header. | |
13 | ||
14 | CUPS is based on the Internet Printing Protocol ("IPP"), which allows clients | |
15 | (applications) to communicate with a server (the scheduler, printers, etc.) to | |
16 | get a list of destinations, send print jobs, and so forth. You identify which | |
17 | server you want to communicate with using a pointer to the opaque structure | |
18 | `http_t`. The `CUPS_HTTP_DEFAULT` constant can be used when you want to talk to | |
19 | the CUPS scheduler. | |
20 | ||
21 | ||
22 | ## Guidelines | |
23 | ||
24 | When writing software that uses the "cups" library: | |
25 | ||
26 | - Do not use undocumented or deprecated APIs, | |
27 | - Do not rely on pre-configured printers, | |
28 | - Do not assume that printers support specific features or formats, and | |
29 | - Do not rely on implementation details (PPDs, etc.) | |
30 | ||
31 | CUPS is designed to insulate users and developers from the implementation | |
32 | details of printers and file formats. The goal is to allow an application to | |
33 | supply a print file in a standard format with the user intent ("print four | |
34 | copies, two-sided on A4 media, and staple each copy") and have the printing | |
35 | system manage the printer communication and format conversion needed. | |
36 | ||
37 | Similarly, printer and job management applications can use standard query | |
38 | operations to obtain the status information in a common, generic form and use | |
39 | standard management operations to control the state of those printers and jobs. | |
40 | ||
41 | ||
42 | ## Terms Used in This Document | |
43 | ||
44 | A *Destination* is a printer or print queue that accepts print jobs. A | |
45 | *Print Job* is one or more documents that are processed by a destination | |
46 | using options supplied when creating the job. A *Document* is a file (JPEG | |
47 | image, PDF file, etc.) suitable for printing. An *Option* controls some aspect | |
48 | of printing, such as the media used. *Media* is the sheets or roll that is | |
49 | printed on. An *Attribute* is an option encoded for an Internet Printing | |
50 | Protocol (IPP) request. | |
51 | ||
52 | ||
53 | ## Compiling Programs That Use the CUPS API | |
54 | ||
55 | The CUPS libraries can be used from any C, C++, or Objective C program. | |
56 | The method of compiling against the libraries varies depending on the | |
57 | operating system and installation of CUPS. The following sections show how | |
58 | to compile a simple program (shown below) in two common environments. | |
59 | ||
60 | The following simple program lists the available destinations: | |
61 | ||
62 | #include <stdio.h> | |
63 | #include <cups/cups.h> | |
64 | ||
65 | int print_dest(void *user_data, unsigned flags, cups_dest_t *dest) | |
66 | { | |
67 | if (dest->instance) | |
68 | printf("%s/%s\n", dest->name, dest->instance); | |
69 | else | |
70 | puts(dest->name); | |
71 | ||
72 | return (1); | |
73 | } | |
74 | ||
75 | int main(void) | |
76 | { | |
77 | cupsEnumDests(CUPS_DEST_FLAGS_NONE, 1000, NULL, 0, 0, print_dest, NULL); | |
78 | ||
79 | return (0); | |
80 | } | |
81 | ||
82 | ||
83 | ### Compiling with Xcode | |
84 | ||
85 | In Xcode, choose *New Project...* from the *File* menu (or press SHIFT+CMD+N), | |
86 | then select the *Command Line Tool* under the macOS Application project type. | |
87 | Click *Next* and enter a name for the project, for example "firstcups". Click | |
88 | *Next* and choose a project directory. The click *Next* to create the project. | |
89 | ||
90 | In the project window, click on the *Build Phases* group and expand the | |
91 | *Link Binary with Libraries* section. Click *+*, type "libcups" to show the | |
92 | library, and then double-click on `libcups.tbd`. | |
93 | ||
94 | Finally, click on the `main.c` file in the sidebar and copy the example program | |
95 | to the file. Build and run (CMD+R) to see the list of destinations. | |
96 | ||
97 | ||
98 | ### Compiling with GCC | |
99 | ||
100 | From the command-line, create a file called `sample.c` using your favorite | |
101 | editor, copy the example to this file, and save. Then run the following command | |
102 | to compile it with GCC and run it: | |
103 | ||
104 | gcc -o simple `cups-config --cflags` simple.c `cups-config --libs` | |
105 | ./simple | |
106 | ||
107 | The `cups-config` command provides the compiler flags (`cups-config --cflags`) | |
108 | and libraries (`cups-config --libs`) needed for the local system. | |
109 | ||
110 | ||
111 | # Working with Destinations | |
112 | ||
113 | ||
114 | ## Finding Available Destinations | |
115 | ||
116 | ||
117 | ## Getting Information About a Destination | |
118 | ||
119 | ||
120 | ### Getting Supported Options and Values | |
121 | ||
122 | cupsCheckDestSupported and cups | |
123 | ||
124 | ### Getting Default Options and Values | |
125 | ||
126 | ### Getting Ready Options and Values | |
127 | ||
128 | ### Media Options | |
129 | ||
130 | ### Other Standard Options | |
131 | ||
132 | ### Localizing Options and Values | |
133 | ||
134 | ## Submitting a Print Job | |
135 | ||
136 | ## Canceling a Print Job | |
137 | ||
138 | ||
139 | # IPP Requests and Responses | |
140 | ||
141 | Why you'd want to do this, etc. | |
142 | ||
143 | ||
144 | ## Connecting to a Destination | |
145 | ||
146 | ## Sending an IPP Request | |
147 | ||
148 | ## Getting the IPP Response | |
149 | ||
150 | ## Handling Authentication | |
151 | ||
152 | ## Handling Certificate Validation | |
153 | ||
154 | ||
155 | ||
156 | ||
157 | ||
158 | ||
159 | ||
160 | ||
161 | ||
162 | ||
163 | ||
164 | ||
165 | ||
166 | ||
167 | ||
168 | ||
169 | ||
170 | ||
171 | ||
172 | <h3><a name='PRINTERS_AND_CLASSES'>Printers and Classes</a></h3> | |
173 | ||
174 | <p>Printers and classes (collections of printers) are accessed through | |
175 | the <a href="#cups_dest_t"><code>cups_dest_t</code></a> structure which | |
176 | includes the name (<code>name</code>), instance (<code>instance</code> - | |
177 | a way of selecting certain saved options/settings), and the options and | |
178 | attributes associated with that destination (<code>num_options</code> and | |
179 | <code>options</code>). Destinations are created using the | |
180 | <a href="#cupsGetDests"><code>cupsGetDests</code></a> function and freed | |
181 | using the <a href='#cupsFreeDests'><code>cupsFreeDests</code></a> function. | |
182 | The <a href='#cupsGetDest'><code>cupsGetDest</code></a> function finds a | |
183 | specific destination for printing:</p> | |
184 | ||
185 | <pre class='example'> | |
186 | #include <cups/cups.h> | |
187 | ||
188 | <a href='#cups_dest_t'>cups_dest_t</a> *dests; | |
189 | int num_dests = <a href='#cupsGetDests'>cupsGetDests</a>(&dests); | |
190 | <a href='#cups_dest_t'>cups_dest_t</a> *dest = <a href='#cupsGetDest'>cupsGetDest</a>("name", NULL, num_dests, dests); | |
191 | ||
192 | /* do something with dest */ | |
193 | ||
194 | <a href='#cupsFreeDests'>cupsFreeDests</a>(num_dests, dests); | |
195 | </pre> | |
196 | ||
197 | <p>Passing <code>NULL</code> to | |
198 | <a href='#cupsGetDest'><code>cupsGetDest</code></a> for the destination name | |
199 | will return the default destination. Similarly, passing a <code>NULL</code> | |
200 | instance will return the default instance for that destination.</p> | |
201 | ||
202 | <div class='table'><table summary='Table 1: Printer Attributes' width='80%'> | |
203 | <caption>Table 1: <a name='TABLE1'>Printer Attributes</a></caption> | |
204 | <thead> | |
205 | <tr> | |
206 | <th>Attribute Name</th> | |
207 | <th>Description</th> | |
208 | </tr> | |
209 | </thead> | |
210 | <tbody> | |
211 | <tr> | |
212 | <td>"auth-info-required"</td> | |
213 | <td>The type of authentication required for printing to this | |
214 | destination: "none", "username,password", "domain,username,password", | |
215 | or "negotiate" (Kerberos)</td> | |
216 | </tr> | |
217 | <tr> | |
218 | <td>"printer-info"</td> | |
219 | <td>The human-readable description of the destination such as "My | |
220 | Laser Printer".</td> | |
221 | </tr> | |
222 | <tr> | |
223 | <td>"printer-is-accepting-jobs"</td> | |
224 | <td>"true" if the destination is accepting new jobs, "false" if | |
225 | not.</td> | |
226 | </tr> | |
227 | <tr> | |
228 | <td>"printer-is-shared"</td> | |
229 | <td>"true" if the destination is being shared with other computers, | |
230 | "false" if not.</td> | |
231 | </tr> | |
232 | <tr> | |
233 | <td>"printer-location"</td> | |
234 | <td>The human-readable location of the destination such as "Lab 4".</td> | |
235 | </tr> | |
236 | <tr> | |
237 | <td>"printer-make-and-model"</td> | |
238 | <td>The human-readable make and model of the destination such as "HP | |
239 | LaserJet 4000 Series".</td> | |
240 | </tr> | |
241 | <tr> | |
242 | <td>"printer-state"</td> | |
243 | <td>"3" if the destination is idle, "4" if the destination is printing | |
244 | a job, and "5" if the destination is stopped.</td> | |
245 | </tr> | |
246 | <tr> | |
247 | <td>"printer-state-change-time"</td> | |
248 | <td>The UNIX time when the destination entered the current state.</td> | |
249 | </tr> | |
250 | <tr> | |
251 | <td>"printer-state-reasons"</td> | |
252 | <td>Additional comma-delimited state keywords for the destination | |
253 | such as "media-tray-empty-error" and "toner-low-warning".</td> | |
254 | </tr> | |
255 | <tr> | |
256 | <td>"printer-type"</td> | |
257 | <td>The <a href='#cups_printer_t'><code>cups_printer_t</code></a> | |
258 | value associated with the destination.</td> | |
259 | </tr> | |
260 | </tbody> | |
261 | </table></div> | |
262 | ||
263 | <h3><a name='OPTIONS'>Options</a></h3> | |
264 | ||
265 | <p>Options are stored in arrays of | |
266 | <a href='#cups_option_t'><code>cups_option_t</code></a> structures. Each | |
267 | option has a name (<code>name</code>) and value (<code>value</code>) | |
268 | associated with it. The <a href='#cups_dest_t'><code>cups_dest_t</code></a> | |
269 | <code>num_options</code> and <code>options</code> members contain the | |
270 | default options for a particular destination, along with several informational | |
271 | attributes about the destination as shown in <a href='#TABLE1'>Table 1</a>. | |
272 | The <a href='#cupsGetOption'><code>cupsGetOption</code></a> function gets | |
273 | the value for the named option. For example, the following code lists the | |
274 | available destinations and their human-readable descriptions:</p> | |
275 | ||
276 | <pre class='example'> | |
277 | #include <cups/cups.h> | |
278 | ||
279 | <a href='#cups_dest_t'>cups_dest_t</a> *dests; | |
280 | int num_dests = <a href='#cupsGetDests'>cupsGetDests</a>(&dests); | |
281 | <a href='#cups_dest_t'>cups_dest_t</a> *dest; | |
282 | int i; | |
283 | const char *value; | |
284 | ||
285 | for (i = num_dests, dest = dests; i > 0; i --, dest ++) | |
286 | if (dest->instance == NULL) | |
287 | { | |
288 | value = <a href='#cupsGetOption'>cupsGetOption</a>("printer-info", dest->num_options, dest->options); | |
289 | printf("%s (%s)\n", dest->name, value ? value : "no description"); | |
290 | } | |
291 | ||
292 | <a href='#cupsFreeDests'>cupsFreeDests</a>(num_dests, dests); | |
293 | </pre> | |
294 | ||
295 | <p>You can create your own option arrays using the | |
296 | <a href='#cupsAddOption'><code>cupsAddOption</code></a> function, which | |
297 | adds a single named option to an array:</p> | |
298 | ||
299 | <pre class='example'> | |
300 | #include <cups/cups.h> | |
301 | ||
302 | int num_options = 0; | |
303 | <a href='#cups_option_t'>cups_option_t</a> *options = NULL; | |
304 | ||
305 | /* The returned num_options value is updated as needed */ | |
306 | num_options = <a href='#cupsAddOption'>cupsAddOption</a>("first", "value", num_options, &options); | |
307 | ||
308 | /* This adds a second option value */ | |
309 | num_options = <a href='#cupsAddOption'>cupsAddOption</a>("second", "value", num_options, &options); | |
310 | ||
311 | /* This replaces the first option we added */ | |
312 | num_options = <a href='#cupsAddOption'>cupsAddOption</a>("first", "new value", num_options, &options); | |
313 | </pre> | |
314 | ||
315 | <p>Use a <code>for</code> loop to copy the options from a destination:</p> | |
316 | ||
317 | <pre class='example'> | |
318 | #include <cups/cups.h> | |
319 | ||
320 | int i; | |
321 | int num_options = 0; | |
322 | <a href='#cups_option_t'>cups_option_t</a> *options = NULL; | |
323 | <a href='#cups_dest_t'>cups_dest_t</a> *dest; | |
324 | ||
325 | for (i = 0; i < dest->num_options; i ++) | |
326 | num_options = <a href='#cupsAddOption'>cupsAddOption</a>(dest->options[i].name, dest->options[i].value, | |
327 | num_options, &options); | |
328 | </pre> | |
329 | ||
330 | <p>Use the <a href='#cupsFreeOptions'><code>cupsFreeOptions</code></a> | |
331 | function to free the options array when you are done using it:</p> | |
332 | ||
333 | <pre class='example'> | |
334 | <a href='#cupsFreeOptions'>cupsFreeOptions</a>(num_options, options); | |
335 | </pre> | |
336 | ||
337 | <h3><a name='PRINT_JOBS'>Print Jobs</a></h3> | |
338 | ||
339 | <p>Print jobs are identified by a locally-unique job ID number from 1 to | |
340 | 2<sup>31</sup>-1 and have options and one or more files for printing to a | |
341 | single destination. The <a href='#cupsPrintFile'><code>cupsPrintFile</code></a> | |
342 | function creates a new job with one file. The following code prints the CUPS | |
343 | test page file:</p> | |
344 | ||
345 | <pre class='example'> | |
346 | #include <cups/cups.h> | |
347 | ||
348 | <a href='#cups_dest_t'>cups_dest_t</a> *dest; | |
349 | int num_options; | |
350 | <a href='#cups_option_t'>cups_option_t</a> *options; | |
351 | int job_id; | |
352 | ||
353 | /* Print a single file */ | |
354 | job_id = <a href='#cupsPrintFile'>cupsPrintFile</a>(dest->name, "/usr/share/cups/data/testprint.ps", | |
355 | "Test Print", num_options, options); | |
356 | </pre> | |
357 | ||
358 | <p>The <a href='#cupsPrintFiles'><code>cupsPrintFiles</code></a> function | |
359 | creates a job with multiple files. The files are provided in a | |
360 | <code>char *</code> array:</p> | |
361 | ||
362 | <pre class='example'> | |
363 | #include <cups/cups.h> | |
364 | ||
365 | <a href='#cups_dest_t'>cups_dest_t</a> *dest; | |
366 | int num_options; | |
367 | <a href='#cups_option_t'>cups_option_t</a> *options; | |
368 | int job_id; | |
369 | char *files[3] = { "file1.pdf", "file2.pdf", "file3.pdf" }; | |
370 | ||
371 | /* Print three files */ | |
372 | job_id = <a href='#cupsPrintFiles'>cupsPrintFiles</a>(dest->name, 3, files, "Test Print", num_options, options); | |
373 | </pre> | |
374 | ||
375 | <p>Finally, the <a href='#cupsCreateJob'><code>cupsCreateJob</code></a> | |
376 | function creates a new job with no files in it. Files are added using the | |
377 | <a href='#cupsStartDocument'><code>cupsStartDocument</code></a>, | |
378 | <a href='api-httpipp.html#cupsWriteRequestData'><code>cupsWriteRequestData</code></a>, | |
379 | and <a href='#cupsFinishDocument'><code>cupsFinishDocument</code></a> functions. | |
380 | The following example creates a job with 10 text files for printing:</p> | |
381 | ||
382 | <pre class='example'> | |
383 | #include <cups/cups.h> | |
384 | ||
385 | <a href='#cups_dest_t'>cups_dest_t</a> *dest; | |
386 | int num_options; | |
387 | <a href='#cups_option_t'>cups_option_t</a> *options; | |
388 | int job_id; | |
389 | int i; | |
390 | char buffer[1024]; | |
391 | ||
392 | /* Create the job */ | |
393 | job_id = <a href='#cupsCreateJob'>cupsCreateJob</a>(CUPS_HTTP_DEFAULT, dest->name, "10 Text Files", | |
394 | num_options, options); | |
395 | ||
396 | /* If the job is created, add 10 files */ | |
397 | if (job_id > 0) | |
398 | { | |
399 | for (i = 1; i <= 10; i ++) | |
400 | { | |
401 | snprintf(buffer, sizeof(buffer), "file%d.txt", i); | |
402 | ||
403 | <a href='#cupsStartDocument'>cupsStartDocument</a>(CUPS_HTTP_DEFAULT, dest->name, job_id, buffer, | |
404 | CUPS_FORMAT_TEXT, i == 10); | |
405 | ||
406 | snprintf(buffer, sizeof(buffer), | |
407 | "File %d\n" | |
408 | "\n" | |
409 | "One fish,\n" | |
410 | "Two fish,\n | |
411 | "Red fish,\n | |
412 | "Blue fish\n", i); | |
413 | ||
414 | /* cupsWriteRequestData can be called as many times as needed */ | |
415 | <a href='#cupsWriteRequestData'>cupsWriteRequestData</a>(CUPS_HTTP_DEFAULT, buffer, strlen(buffer)); | |
416 | ||
417 | <a href='#cupsFinishDocument'>cupsFinishDocument</a>(CUPS_HTTP_DEFAULT, dest->name); | |
418 | } | |
419 | } | |
420 | </pre> | |
421 | ||
422 | <p>Once you have created a job, you can monitor its status using the | |
423 | <a href='#cupsGetJobs'><code>cupsGetJobs</code></a> function, which returns | |
424 | an array of <a href='#cups_job_t'><code>cups_job_t</code></a> structures. | |
425 | Each contains the job ID (<code>id</code>), destination name | |
426 | (<code>dest</code>), title (<code>title</code>), and other information | |
427 | associated with the job. The job array is freed using the | |
428 | <a href='#cupsFreeJobs'><code>cupsFreeJobs</code></a> function. The following | |
429 | example monitors a specific job ID, showing the current job state once every | |
430 | 5 seconds until the job is completed:</p> | |
431 | ||
432 | <pre class='example'> | |
433 | #include <cups/cups.h> | |
434 | ||
435 | <a href='#cups_dest_t'>cups_dest_t</a> *dest; | |
436 | int job_id; | |
437 | int num_jobs; | |
438 | <a href='#cups_job_t'>cups_job_t</a> *jobs; | |
439 | int i; | |
440 | ipp_jstate_t job_state = IPP_JOB_PENDING; | |
441 | ||
442 | while (job_state < IPP_JOB_STOPPED) | |
443 | { | |
444 | /* Get my jobs (1) with any state (-1) */ | |
445 | num_jobs = <a href='#cupsGetJobs'>cupsGetJobs</a>(&jobs, dest->name, 1, -1); | |
446 | ||
447 | /* Loop to find my job */ | |
448 | job_state = IPP_JOB_COMPLETED; | |
449 | ||
450 | for (i = 0; i < num_jobs; i ++) | |
451 | if (jobs[i].id == job_id) | |
452 | { | |
453 | job_state = jobs[i].state; | |
454 | break; | |
455 | } | |
456 | ||
457 | /* Free the job array */ | |
458 | <a href='#cupsFreeJobs'>cupsFreeJobs</a>(num_jobs, jobs); | |
459 | ||
460 | /* Show the current state */ | |
461 | switch (job_state) | |
462 | { | |
463 | case IPP_JOB_PENDING : | |
464 | printf("Job %d is pending.\n", job_id); | |
465 | break; | |
466 | case IPP_JOB_HELD : | |
467 | printf("Job %d is held.\n", job_id); | |
468 | break; | |
469 | case IPP_JOB_PROCESSING : | |
470 | printf("Job %d is processing.\n", job_id); | |
471 | break; | |
472 | case IPP_JOB_STOPPED : | |
473 | printf("Job %d is stopped.\n", job_id); | |
474 | break; | |
475 | case IPP_JOB_CANCELED : | |
476 | printf("Job %d is canceled.\n", job_id); | |
477 | break; | |
478 | case IPP_JOB_ABORTED : | |
479 | printf("Job %d is aborted.\n", job_id); | |
480 | break; | |
481 | case IPP_JOB_COMPLETED : | |
482 | printf("Job %d is completed.\n", job_id); | |
483 | break; | |
484 | } | |
485 | ||
486 | /* Sleep if the job is not finished */ | |
487 | if (job_state < IPP_JOB_STOPPED) | |
488 | sleep(5); | |
489 | } | |
490 | </pre> | |
491 | ||
492 | <p>To cancel a job, use the | |
493 | <a href='#cupsCancelJob'><code>cupsCancelJob</code></a> function with the | |
494 | job ID:</p> | |
495 | ||
496 | <pre class='example'> | |
497 | #include <cups/cups.h> | |
498 | ||
499 | <a href='#cups_dest_t'>cups_dest_t</a> *dest; | |
500 | int job_id; | |
501 | ||
502 | <a href='#cupsCancelJob'>cupsCancelJob</a>(dest->name, job_id); | |
503 | </pre> | |
504 | ||
505 | <h3><a name='ERROR_HANDLING'>Error Handling</a></h3> | |
506 | ||
507 | <p>If any of the CUPS API printing functions returns an error, the reason for | |
508 | that error can be found by calling the | |
509 | <a href='#cupsLastError'><code>cupsLastError</code></a> and | |
510 | <a href='#cupsLastErrorString'><code>cupsLastErrorString</code></a> functions. | |
511 | <a href='#cupsLastError'><code>cupsLastError</code></a> returns the last IPP | |
512 | error code | |
513 | (<a href='api-httpipp.html#ipp_status_t'><code>ipp_status_t</code></a>) | |
514 | that was encountered, while | |
515 | <a href='#cupsLastErrorString'><code>cupsLastErrorString</code></a> returns | |
516 | a (localized) human-readable string that can be shown to the user. For example, | |
517 | if any of the job creation functions returns a job ID of 0, you can use | |
518 | <a href='#cupsLastErrorString'><code>cupsLastErrorString</code></a> to show | |
519 | the reason why the job could not be created:</p> | |
520 | ||
521 | <pre class='example'> | |
522 | #include <cups/cups.h> | |
523 | ||
524 | int job_id; | |
525 | ||
526 | if (job_id == 0) | |
527 | puts(cupsLastErrorString()); | |
528 | </pre> | |
529 | ||
530 | <h3><a name='PASSWORDS_AND_AUTHENTICATION'>Passwords and Authentication</a></h3> | |
531 | ||
532 | <p>CUPS supports authentication of any request, including submission of print | |
533 | jobs. The default mechanism for getting the username and password is to use the | |
534 | login user and a password from the console.</p> | |
535 | ||
536 | <p>To support other types of applications, in particular Graphical User | |
537 | Interfaces ("GUIs"), the CUPS API provides functions to set the default | |
538 | username and to register a callback function that returns a password string.</p> | |
539 | ||
540 | <p>The <a href="#cupsSetPasswordCB"><code>cupsSetPasswordCB</code></a> | |
541 | function is used to set a password callback in your program. Only one | |
542 | function can be used at any time.</p> | |
543 | ||
544 | <p>The <a href="#cupsSetUser"><code>cupsSetUser</code></a> function sets the | |
545 | current username for authentication. This function can be called by your | |
546 | password callback function to change the current username as needed.</p> | |
547 | ||
548 | <p>The following example shows a simple password callback that gets a | |
549 | username and password from the user:</p> | |
550 | ||
551 | <pre class='example'> | |
552 | #include <cups/cups.h> | |
553 | ||
554 | const char * | |
555 | my_password_cb(const char *prompt) | |
556 | { | |
557 | char user[65]; | |
558 | ||
559 | ||
560 | puts(prompt); | |
561 | ||
562 | /* Get a username from the user */ | |
563 | printf("Username: "); | |
564 | if (fgets(user, sizeof(user), stdin) == NULL) | |
565 | return (NULL); | |
566 | ||
567 | /* Strip the newline from the string and set the user */ | |
568 | user[strlen(user) - 1] = '\0'; | |
569 | ||
570 | <a href='#cupsSetUser'>cupsSetUser</a>(user); | |
571 | ||
572 | /* Use getpass() to ask for the password... */ | |
573 | return (getpass("Password: ")); | |
574 | } | |
575 | ||
576 | <a href='#cupsSetPasswordCB'>cupsSetPasswordCB</a>(my_password_cb); | |
577 | </pre> | |
578 | ||
579 | <p>Similarly, a GUI could display the prompt string in a window with input | |
580 | fields for the username and password. The username should default to the | |
581 | string returned by the <a href="#cupsUser"><code>cupsUser</code></a> | |
582 | function.</p> | |
583 | <!-- | |
584 | HTTP and IPP API introduction for CUPS. | |
585 | ||
586 | Copyright 2007-2012 by Apple Inc. | |
587 | Copyright 1997-2006 by Easy Software Products, all rights reserved. | |
588 | ||
589 | These coded instructions, statements, and computer programs are the | |
590 | property of Apple Inc. and are protected by Federal copyright | |
591 | law. Distribution and use rights are outlined in the file "LICENSE.txt" | |
592 | which should have been included with this file. If this file is | |
593 | file is missing or damaged, see the license at "http://www.cups.org/". | |
594 | --> | |
595 | ||
596 | <h2 class='title'><a name='OVERVIEW'>Overview</a></h2> | |
597 | ||
598 | <p>The CUPS HTTP and IPP APIs provide low-level access to the HTTP and IPP | |
599 | protocols and CUPS scheduler. They are typically used by monitoring and | |
600 | administration programs to perform specific functions not supported by the | |
601 | high-level CUPS API functions.</p> | |
602 | ||
603 | <p>The HTTP APIs use an opaque structure called | |
604 | <a href='#http_t'><code>http_t</code></a> to manage connections to | |
605 | a particular HTTP or IPP server. The | |
606 | <a href='#httpConnectEncrypt'><code>httpConnectEncrypt</code></a> function is | |
607 | used to create an instance of this structure for a particular server. | |
608 | The constant <code>CUPS_HTTP_DEFAULT</code> can be used with all of the | |
609 | <code>cups</code> functions to refer to the default CUPS server - the functions | |
610 | create a per-thread <a href='#http_t'><code>http_t</code></a> as needed.</p> | |
611 | ||
612 | <p>The IPP APIs use two opaque structures for requests (messages sent to the CUPS scheduler) and responses (messages sent back to your application from the scheduler). The <a href='#ipp_t'><code>ipp_t</code></a> type holds a complete request or response and is allocated using the <a href='#ippNew'><code>ippNew</code></a> or <a href='#ippNewRequest'><code>ippNewRequest</code></a> functions and freed using the <a href='#ippDelete'><code>ippDelete</code></a> function.</p> | |
613 | ||
614 | <p>The second opaque structure is called <a href='#ipp_attribute_t'><code>ipp_attribute_t</code></a> and holds a single IPP attribute which consists of a group tag (<a href='#ippGetGroupTag'><code>ippGetGroupTag</code></a>), a value type tag (<a href='#ippGetValueTag'><code>ippGetValueTag</code></a>), the attribute name (<a href='#ippGetName'><code>ippGetName</code></a>), and 1 or more values (<a href='#ippGetCount'><code>ippGetCount</code></a>, <a href='#ippGetBoolean'><code>ippGetBoolean</code></a>, <a href='#ippGetCollection'><code>ippGetCollection</code></a>, <a href='#ippGetDate'><code>ippGetDate</code></a>, <a href='#ippGetInteger'><code>ippGetInteger</code></a>, <a href='#ippGetRange'><code>ippGetRange</code></a>, <a href='#ippGetResolution'><code>ippGetResolution</code></a>, and <a href='#ippGetString'><code>ippGetString</code></a>). Attributes are added to an <a href='#ipp_t'><code>ipp_t</code></a> pointer using one of the <code>ippAdd</code> functions. For example, use <a href='#ippAddString'><code>ippAddString</code></a> to add the "printer-uri" and "requesting-user-name" string attributes to a request:</p> | |
615 | ||
616 | <pre class='example'> | |
617 | <a href='#ipp_t'>ipp_t</a> *request = <a href='#ippNewRequest'>ippNewRequest</a>(IPP_GET_JOBS); | |
618 | ||
619 | <a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", | |
620 | NULL, "ipp://localhost/printers/"); | |
621 | <a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", | |
622 | NULL, cupsUser()); | |
623 | </pre> | |
624 | ||
625 | <p>Once you have created an IPP request, use the <code>cups</code> functions to send the request to and read the response from the server. For example, the <a href='#cupsDoRequest'><code>cupsDoRequest</code></a> function can be used for simple query operations that do not involve files:</p> | |
626 | ||
627 | <pre class='example'> | |
628 | #include <cups/cups.h> | |
629 | ||
630 | ||
631 | <a href='#ipp_t'>ipp_t</a> *<a name='get_jobs'>get_jobs</a>(void) | |
632 | { | |
633 | <a href='#ipp_t'>ipp_t</a> *request = <a href='#ippNewRequest'>ippNewRequest</a>(IPP_GET_JOBS); | |
634 | ||
635 | <a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", | |
636 | NULL, "ipp://localhost/printers/"); | |
637 | <a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", | |
638 | NULL, cupsUser()); | |
639 | ||
640 | return (<a href='#cupsDoRequest'>cupsDoRequest</a>(CUPS_HTTP_DEFAULT, request, "/")); | |
641 | } | |
642 | </pre> | |
643 | ||
644 | <p>The <a href='#cupsDoRequest'><code>cupsDoRequest</code></a> function frees the request and returns an IPP response or <code>NULL</code> pointer if the request could not be sent to the server. Once you have a response from the server, you can either use the <a href='#ippFindAttribute'><code>ippFindAttribute</code></a> and <a href='#ippFindNextAttribute'><code>ippFindNextAttribute</code></a> functions to find specific attributes, for example:</p> | |
645 | ||
646 | <pre class='example'> | |
647 | <a href='#ipp_t'>ipp_t</a> *response; | |
648 | <a href='#ipp_attribute_t'>ipp_attribute_t</a> *attr; | |
649 | ||
650 | attr = <a href='#ippFindAttribute'>ippFindAttribute</a>(response, "printer-state", IPP_TAG_ENUM); | |
651 | </pre> | |
652 | ||
653 | <p>You can also walk the list of attributes with a simple <code>for</code> loop like this:</p> | |
654 | ||
655 | <pre class='example'> | |
656 | <a href='#ipp_t'>ipp_t</a> *response; | |
657 | <a href='#ipp_attribute_t'>ipp_attribute_t</a> *attr; | |
658 | ||
659 | for (attr = <a href='#ippFirstAttribute'>ippFirstAttribute</a>(response); attr != NULL; attr = <a href='#ippNextAttribute'>ippNextAttribute</a>(response)) | |
660 | if (ippGetName(attr) == NULL) | |
661 | puts("--SEPARATOR--"); | |
662 | else | |
663 | puts(ippGetName(attr)); | |
664 | </pre> | |
665 | ||
666 | <p>The <code>for</code> loop approach is normally used when collecting attributes for multiple objects (jobs, printers, etc.) in a response. Attributes with <code>NULL</code> names indicate a separator between the attributes of each object. For example, the following code will list the jobs returned from our previous <a href='#get_jobs'><code>get_jobs</code></a> example code:</p> | |
667 | ||
668 | <pre class='example'> | |
669 | <a href='#ipp_t'>ipp_t</a> *response = <a href='#get_jobs'>get_jobs</a>(); | |
670 | ||
671 | if (response != NULL) | |
672 | { | |
673 | <a href='#ipp_attribute_t'>ipp_attribute_t</a> *attr; | |
674 | const char *attrname; | |
675 | int job_id = 0; | |
676 | const char *job_name = NULL; | |
677 | const char *job_originating_user_name = NULL; | |
678 | ||
679 | puts("Job ID Owner Title"); | |
680 | puts("------ ---------------- ---------------------------------"); | |
681 | ||
682 | for (attr = <a href='#ippFirstAttribute'>ippFirstAttribute</a>(response); attr != NULL; attr = <a href='#ippNextAttribute'>ippNextAttribute</a>(response)) | |
683 | { | |
684 | /* Attributes without names are separators between jobs */ | |
685 | attrname = ippGetName(attr); | |
686 | if (attrname == NULL) | |
687 | { | |
688 | if (job_id > 0) | |
689 | { | |
690 | if (job_name == NULL) | |
691 | job_name = "(withheld)"; | |
692 | ||
693 | if (job_originating_user_name == NULL) | |
694 | job_originating_user_name = "(withheld)"; | |
695 | ||
696 | printf("%5d %-16s %s\n", job_id, job_originating_user_name, job_name); | |
697 | } | |
698 | ||
699 | job_id = 0; | |
700 | job_name = NULL; | |
701 | job_originating_user_name = NULL; | |
702 | continue; | |
703 | } | |
704 | else if (!strcmp(attrname, "job-id") && ippGetValueTag(attr) == IPP_TAG_INTEGER) | |
705 | job_id = ippGetInteger(attr, 0); | |
706 | else if (!strcmp(attrname, "job-name") && ippGetValueTag(attr) == IPP_TAG_NAME) | |
707 | job_name = ippGetString(attr, 0, NULL); | |
708 | else if (!strcmp(attrname, "job-originating-user-name") && | |
709 | ippGetValueTag(attr) == IPP_TAG_NAME) | |
710 | job_originating_user_name = ippGetString(attr, 0, NULL); | |
711 | } | |
712 | ||
713 | if (job_id > 0) | |
714 | { | |
715 | if (job_name == NULL) | |
716 | job_name = "(withheld)"; | |
717 | ||
718 | if (job_originating_user_name == NULL) | |
719 | job_originating_user_name = "(withheld)"; | |
720 | ||
721 | printf("%5d %-16s %s\n", job_id, job_originating_user_name, job_name); | |
722 | } | |
723 | } | |
724 | </pre> | |
725 | ||
726 | <h3><a name='CREATING_URI_STRINGS'>Creating URI Strings</a></h3> | |
727 | ||
728 | <p>To ensure proper encoding, the | |
729 | <a href='#httpAssembleURIf'><code>httpAssembleURIf</code></a> function must be | |
730 | used to format a "printer-uri" string for all printer-based requests:</p> | |
731 | ||
732 | <pre class='example'> | |
733 | const char *name = "Foo"; | |
734 | char uri[1024]; | |
735 | <a href='#ipp_t'>ipp_t</a> *request; | |
736 | ||
737 | <a href='#httpAssembleURIf'>httpAssembleURIf</a>(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, cupsServer(), | |
738 | ippPort(), "/printers/%s", name); | |
739 | <a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); | |
740 | </pre> | |
741 | ||
742 | <h3><a name='SENDING_REQUESTS_WITH_FILES'>Sending Requests with Files</a></h3> | |
743 | ||
744 | <p>The <a href='#cupsDoFileRequest'><code>cupsDoFileRequest</code></a> and | |
745 | <a href='#cupsDoIORequest'><code>cupsDoIORequest</code></a> functions are | |
746 | used for requests involving files. The | |
747 | <a href='#cupsDoFileRequest'><code>cupsDoFileRequest</code></a> function | |
748 | attaches the named file to a request and is typically used when sending a print | |
749 | file or changing a printer's PPD file:</p> | |
750 | ||
751 | <pre class='example'> | |
752 | const char *filename = "/usr/share/cups/data/testprint.ps"; | |
753 | const char *name = "Foo"; | |
754 | char uri[1024]; | |
755 | char resource[1024]; | |
756 | <a href='#ipp_t'>ipp_t</a> *request = <a href='#ippNewRequest'>ippNewRequest</a>(IPP_PRINT_JOB); | |
757 | <a href='#ipp_t'>ipp_t</a> *response; | |
758 | ||
759 | /* Use httpAssembleURIf for the printer-uri string */ | |
760 | <a href='#httpAssembleURIf'>httpAssembleURIf</a>(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, cupsServer(), | |
761 | ippPort(), "/printers/%s", name); | |
762 | <a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); | |
763 | <a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", | |
764 | NULL, cupsUser()); | |
765 | <a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", | |
766 | NULL, "testprint.ps"); | |
767 | ||
768 | /* Use snprintf for the resource path */ | |
769 | snprintf(resource, sizeof(resource), "/printers/%s", name); | |
770 | ||
771 | response = <a href='#cupsDoFileRequest'>cupsDoFileRequest</a>(CUPS_HTTP_DEFAULT, request, resource, filename); | |
772 | </pre> | |
773 | ||
774 | <p>The <a href='#cupsDoIORequest'><code>cupsDoIORequest</code></a> function | |
775 | optionally attaches a file to the request and optionally saves a file in the | |
776 | response from the server. It is used when using a pipe for the request | |
777 | attachment or when using a request that returns a file, currently only | |
778 | <code>CUPS_GET_DOCUMENT</code> and <code>CUPS_GET_PPD</code>. For example, | |
779 | the following code will download the PPD file for the sample HP LaserJet | |
780 | printer driver:</p> | |
781 | ||
782 | <pre class='example'> | |
783 | char tempfile[1024]; | |
784 | int tempfd; | |
785 | <a href='#ipp_t'>ipp_t</a> *request = <a href='#ippNewRequest'>ippNewRequest</a>(CUPS_GET_PPD); | |
786 | <a href='#ipp_t'>ipp_t</a> *response; | |
787 | ||
788 | <a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name", | |
789 | NULL, "laserjet.ppd"); | |
790 | ||
791 | tempfd = cupsTempFd(tempfile, sizeof(tempfile)); | |
792 | ||
793 | response = <a href='#cupsDoIORequest'>cupsDoIORequest</a>(CUPS_HTTP_DEFAULT, request, "/", -1, tempfd); | |
794 | </pre> | |
795 | ||
796 | <p>The example passes <code>-1</code> for the input file descriptor to specify | |
797 | that no file is to be attached to the request. The PPD file attached to the | |
798 | response is written to the temporary file descriptor we created using the | |
799 | <code>cupsTempFd</code> function.</p> | |
800 | ||
801 | <h3><a name='ASYNCHRONOUS_REQUEST_PROCESSING'>Asynchronous Request Processing</a></h3> | |
802 | ||
803 | <p>The <a href='#cupsSendRequest'><code>cupsSendRequest</code></a> and | |
804 | <a href='#cupsGetResponse'><code>cupsGetResponse</code></a> support | |
805 | asynchronous communications with the server. Unlike the other request | |
806 | functions, the IPP request is not automatically freed, so remember to | |
807 | free your request with the <a href='#ippDelete'><code>ippDelete</code></a> | |
808 | function.</p> | |
809 | ||
810 | <p>File data is attached to the request using the | |
811 | <a href='#cupsWriteRequestData'><code>cupsWriteRequestData</code></a> | |
812 | function, while file data returned from the server is read using the | |
813 | <a href='#cupsReadResponseData'><code>cupsReadResponseData</code></a> | |
814 | function. We can rewrite the previous <code>CUPS_GET_PPD</code> example | |
815 | to use the asynchronous functions quite easily:</p> | |
816 | ||
817 | <pre class='example'> | |
818 | char tempfile[1024]; | |
819 | int tempfd; | |
820 | <a href='#ipp_t'>ipp_t</a> *request = <a href='#ippNewRequest'>ippNewRequest</a>(CUPS_GET_PPD); | |
821 | <a href='#ipp_t'>ipp_t</a> *response; | |
822 | ||
823 | <a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name", | |
824 | NULL, "laserjet.ppd"); | |
825 | ||
826 | tempfd = cupsTempFd(tempfile, sizeof(tempfile)); | |
827 | ||
828 | if (<a href='#cupsSendRequest'>cupsSendRequest</a>(CUPS_HTTP_DEFAULT, request, "/") == HTTP_CONTINUE) | |
829 | { | |
830 | response = <a href='#cupsGetResponse'>cupsGetResponse</a>(CUPS_HTTP_DEFAULT, "/"); | |
831 | ||
832 | if (response != NULL) | |
833 | { | |
834 | ssize_t bytes; | |
835 | char buffer[8192]; | |
836 | ||
837 | while ((bytes = <a href='#cupsReadResponseData'>cupsReadResponseData</a>(CUPS_HTTP_DEFAULT, buffer, sizeof(buffer))) > 0) | |
838 | write(tempfd, buffer, bytes); | |
839 | } | |
840 | } | |
841 | ||
842 | /* Free the request! */ | |
843 | <a href='#ippDelete'>ippDelete</a>(request); | |
844 | </pre> | |
845 | ||
846 | <p>The <a href='#cupsSendRequest'><code>cupsSendRequest</code></a> function | |
847 | returns the initial HTTP request status, typically either | |
848 | <code>HTTP_CONTINUE</code> or <code>HTTP_UNAUTHORIZED</code>. The latter status | |
849 | is returned when the request requires authentication of some sort. The | |
850 | <a href='#cupsDoAuthentication'><code>cupsDoAuthentication</code></a> function | |
851 | must be called when your see <code>HTTP_UNAUTHORIZED</code> and the request | |
852 | re-sent. We can add authentication support to our example code by using a | |
853 | <code>do ... while</code> loop:</p> | |
854 | ||
855 | <pre class='example'> | |
856 | char tempfile[1024]; | |
857 | int tempfd; | |
858 | <a href='#ipp_t'>ipp_t</a> *request = <a href='#ippNewRequest'>ippNewRequest</a>(CUPS_GET_PPD); | |
859 | <a href='#ipp_t'>ipp_t</a> *response; | |
860 | http_status_t status; | |
861 | ||
862 | <a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name", | |
863 | NULL, "laserjet.ppd"); | |
864 | ||
865 | tempfd = cupsTempFd(tempfile, sizeof(tempfile)); | |
866 | ||
867 | /* Loop for authentication */ | |
868 | do | |
869 | { | |
870 | status = <a href='#cupsSendRequest'>cupsSendRequest</a>(CUPS_HTTP_DEFAULT, request, "/"); | |
871 | ||
872 | if (status == HTTP_UNAUTHORIZED) | |
873 | { | |
874 | /* Try to authenticate, break out of the loop if that fails */ | |
875 | if (<a href='#cupsDoAuthentication'>cupsDoAuthentication</a>(CUPS_HTTP_DEFAULT, "POST", "/")) | |
876 | break; | |
877 | } | |
878 | } | |
879 | while (status != HTTP_CONTINUE && status != HTTP_UNAUTHORIZED); | |
880 | ||
881 | if (status == HTTP_CONTINUE) | |
882 | { | |
883 | response = <a href='#cupsGetResponse'>cupsGetResponse</a>(CUPS_HTTP_DEFAULT, "/"); | |
884 | ||
885 | if (response != NULL) | |
886 | { | |
887 | ssize_t bytes; | |
888 | char buffer[8192]; | |
889 | ||
890 | while ((bytes = <a href='#cupsReadResponseData'>cupsReadResponseData</a>(CUPS_HTTP_DEFAULT, buffer, sizeof(buffer))) > 0) | |
891 | write(tempfd, buffer, bytes); | |
892 | } | |
893 | } | |
894 | ||
895 | /* Free the request! */ | |
896 | <a href='#ippDelete'>ippDelete</a>(request); | |
897 | </pre> | |
898 | <!-- | |
899 | File and directory API introduction for CUPS. | |
900 | ||
901 | Copyright 2007-2011 by Apple Inc. | |
902 | Copyright 1997-2005 by Easy Software Products, all rights reserved. | |
903 | ||
904 | These coded instructions, statements, and computer programs are the | |
905 | property of Apple Inc. and are protected by Federal copyright | |
906 | law. Distribution and use rights are outlined in the file "LICENSE.txt" | |
907 | which should have been included with this file. If this file is | |
908 | file is missing or damaged, see the license at "http://www.cups.org/". | |
909 | --> | |
910 | ||
911 | <h2 class='title'><a name="OVERVIEW">Overview</a></h2> | |
912 | ||
913 | <p>The CUPS file and directory APIs provide portable interfaces | |
914 | for manipulating files and listing files and directories. Unlike | |
915 | stdio <code>FILE</code> streams, the <code>cupsFile</code> functions | |
916 | allow you to open more than 256 files at any given time. They | |
917 | also manage the platform-specific details of locking, large file | |
918 | support, line endings (CR, LF, or CR LF), and reading and writing | |
919 | files using Flate ("gzip") compression. Finally, you can also | |
920 | connect, read from, and write to network connections using the | |
921 | <code>cupsFile</code> functions.</p> | |
922 | ||
923 | <p>The <code>cupsDir</code> functions manage the platform-specific | |
924 | details of directory access/listing and provide a convenient way | |
925 | to get both a list of files and the information (permissions, | |
926 | size, timestamp, etc.) for each of those files.</p> | |
927 | <!-- | |
928 | Array API introduction for CUPS. | |
929 | ||
930 | Copyright 2007-2011 by Apple Inc. | |
931 | Copyright 1997-2006 by Easy Software Products, all rights reserved. | |
932 | ||
933 | These coded instructions, statements, and computer programs are the | |
934 | property of Apple Inc. and are protected by Federal copyright | |
935 | law. Distribution and use rights are outlined in the file "LICENSE.txt" | |
936 | which should have been included with this file. If this file is | |
937 | file is missing or damaged, see the license at "http://www.cups.org/". | |
938 | --> | |
939 | ||
940 | <h2 class='title'><a name='OVERVIEW'>Overview</a></h2> | |
941 | ||
942 | <p>The CUPS array API provides a high-performance generic array container. | |
943 | The contents of the array container can be sorted and the container itself is | |
944 | designed for optimal speed and memory usage under a wide variety of conditions. | |
945 | Sorted arrays use a binary search algorithm from the last found or inserted | |
946 | element to quickly find matching elements in the array. Arrays created with the | |
947 | optional hash function can often find elements with a single lookup. The | |
948 | <a href='#cups_array_t'><code>cups_array_t</code></a> type is used when | |
949 | referring to a CUPS array.</p> | |
950 | ||
951 | <p>The CUPS scheduler (<tt>cupsd</tt>) and many of the CUPS API | |
952 | functions use the array API to efficiently manage large lists of | |
953 | data.</p> | |
954 | ||
955 | <h3><a name='MANAGING_ARRAYS'>Managing Arrays</a></h3> | |
956 | ||
957 | <p>Arrays are created using either the | |
958 | <a href='#cupsArrayNew'><code>cupsArrayNew</code></a>, | |
959 | <a href='#cupsArrayNew2'><code>cupsArrayNew2</code></a>, or | |
960 | <a href='#cupsArrayNew2'><code>cupsArrayNew3</code></a> functions. The | |
961 | first function creates a new array with the specified callback function | |
962 | and user data pointer:</p> | |
963 | ||
964 | <pre class='example'> | |
965 | #include <cups/array.h> | |
966 | ||
967 | static int compare_func(void *first, void *second, void *user_data); | |
968 | ||
969 | void *user_data; | |
970 | <a href='#cups_array_t'>cups_array_t</a> *array = <a href='#cupsArrayNew'>cupsArrayNew</a>(compare_func, user_data); | |
971 | </pre> | |
972 | ||
973 | <p>The comparison function (type | |
974 | <a href="#cups_arrayfunc_t"><code>cups_arrayfunc_t</code></a>) is called | |
975 | whenever an element is added to the array and can be <code>NULL</code> to | |
976 | create an unsorted array. The function returns -1 if the first element should | |
977 | come before the second, 0 if the first and second elements should have the same | |
978 | ordering, and 1 if the first element should come after the second.</p> | |
979 | ||
980 | <p>The "user_data" pointer is passed to your comparison function. Pass | |
981 | <code>NULL</code> if you do not need to associate the elements in your array | |
982 | with additional information.</p> | |
983 | ||
984 | <p>The <a href='#cupsArrayNew2'><code>cupsArrayNew2</code></a> function adds | |
985 | two more arguments to support hashed lookups, which can potentially provide | |
986 | instantaneous ("O(1)") lookups in your array:</p> | |
987 | ||
988 | <pre class='example'> | |
989 | #include <cups/array.h> | |
990 | ||
991 | #define HASH_SIZE 512 /* Size of hash table */ | |
992 | ||
993 | static int compare_func(void *first, void *second, void *user_data); | |
994 | static int hash_func(void *element, void *user_data); | |
995 | ||
996 | void *user_data; | |
997 | <a href='#cups_array_t'>cups_array_t</a> *hash_array = <a href='#cupsArrayNew2'>cupsArrayNew2</a>(compare_func, user_data, hash_func, HASH_SIZE); | |
998 | </pre> | |
999 | ||
1000 | <p>The hash function (type | |
1001 | <a href="#cups_ahash_func_t"><code>cups_ahash_func_t</code></a>) should return a | |
1002 | number from 0 to (hash_size-1) that (hopefully) uniquely identifies the | |
1003 | element and is called whenever you look up an element in the array with | |
1004 | <a href='#cupsArrayFind'><code>cupsArrayFind</code></a>. The hash size is | |
1005 | only limited by available memory, but generally should not be larger than | |
1006 | 16384 to realize any performance improvement.</p> | |
1007 | ||
1008 | <p>The <a href='#cupsArrayNew3'><code>cupsArrayNew3</code></a> function adds | |
1009 | copy and free callbacks to support basic memory management of elements:</p> | |
1010 | ||
1011 | <pre class='example'> | |
1012 | #include <cups/array.h> | |
1013 | ||
1014 | #define HASH_SIZE 512 /* Size of hash table */ | |
1015 | ||
1016 | static int compare_func(void *first, void *second, void *user_data); | |
1017 | static void *copy_func(void *element, void *user_data); | |
1018 | static void free_func(void *element, void *user_data); | |
1019 | static int hash_func(void *element, void *user_data); | |
1020 | ||
1021 | void *user_data; | |
1022 | <a href='#cups_array_t'>cups_array_t</a> *array = <a href='#cupsArrayNew3'>cupsArrayNew3</a>(compare_func, user_data, NULL, 0, copy_func, free_func); | |
1023 | ||
1024 | <a href='#cups_array_t'>cups_array_t</a> *hash_array = <a href='#cupsArrayNew3'>cupsArrayNew3</a>(compare_func, user_data, hash_func, HASH_SIZE, copy_func, free_func); | |
1025 | </pre> | |
1026 | ||
1027 | <p>Once you have created the array, you add elements using the | |
1028 | <a href='#cupsArrayAdd'><code>cupsArrayAdd</code></a> | |
1029 | <a href='#cupsArrayInsert'><code>cupsArrayInsert</code></a> functions. | |
1030 | The first function adds an element to the array, adding the new element | |
1031 | after any elements that have the same order, while the second inserts the | |
1032 | element before others with the same order. For unsorted arrays, | |
1033 | <a href='#cupsArrayAdd'><code>cupsArrayAdd</code></a> appends the element to | |
1034 | the end of the array while | |
1035 | <a href='#cupsArrayInsert'><code>cupsArrayInsert</code></a> inserts the | |
1036 | element at the beginning of the array. For example, the following code | |
1037 | creates a sorted array of character strings:</p> | |
1038 | ||
1039 | <pre class='example'> | |
1040 | #include <cups/array.h> | |
1041 | ||
1042 | /* Use strcmp() to compare strings - it will ignore the user_data pointer */ | |
1043 | <a href='#cups_array_t'>cups_array_t</a> *array = <a href='#cupsArrayNew'>cupsArrayNew</a>((<a href='#cups_array_func_t'>cups_array_func_t</a>)strcmp, NULL); | |
1044 | ||
1045 | /* Add four strings to the array */ | |
1046 | <a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "One Fish"); | |
1047 | <a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Two Fish"); | |
1048 | <a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Red Fish"); | |
1049 | <a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Blue Fish"); | |
1050 | </pre> | |
1051 | ||
1052 | <p>Elements are removed using the | |
1053 | <a href='#cupsArrayRemove'><code>cupsArrayRemove</code></a> function, for | |
1054 | example:</p> | |
1055 | ||
1056 | <pre class='example'> | |
1057 | #include <cups/array.h> | |
1058 | ||
1059 | /* Use strcmp() to compare strings - it will ignore the user_data pointer */ | |
1060 | <a href='#cups_array_t'>cups_array_t</a> *array = <a href='#cupsArrayNew'>cupsArrayNew</a>((<a href='#cups_array_func_t'>cups_array_func_t</a>)strcmp, NULL); | |
1061 | ||
1062 | /* Add four strings to the array */ | |
1063 | <a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "One Fish"); | |
1064 | <a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Two Fish"); | |
1065 | <a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Red Fish"); | |
1066 | <a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Blue Fish"); | |
1067 | ||
1068 | /* Remove "Red Fish" */ | |
1069 | <a href='#cupsArrayRemove'>cupsArrayRemove</a>(array, "Red Fish"); | |
1070 | </pre> | |
1071 | ||
1072 | <p>Finally, you free the memory used by the array using the | |
1073 | <a href='#cupsArrayDelete'><code>cupsArrayDelete</code></a> function. All | |
1074 | of the memory for the array and hash table (if any) is freed, however <em>CUPS | |
1075 | does not free the elements unless you provide copy and free functions</em>.</p> | |
1076 | ||
1077 | <h3><a name='FINDING_AND_ENUMERATING'>Finding and Enumerating Elements</a></h3> | |
1078 | ||
1079 | <p>CUPS provides several functions to find and enumerate elements in an | |
1080 | array. Each one sets or updates a "current index" into the array, such that | |
1081 | future lookups will start where the last one left off:</p> | |
1082 | ||
1083 | <dl> | |
1084 | <dt><a href='#cupsArrayFind'><code>cupsArrayFind</code></a></dt> | |
1085 | <dd>Returns the first matching element.</dd> | |
1086 | <dt><a href='#cupsArrayFirst'><code>cupsArrayFirst</code></a></dt> | |
1087 | <dd>Returns the first element in the array.</dd> | |
1088 | <dt><a href='#cupsArrayIndex'><code>cupsArrayIndex</code></a></dt> | |
1089 | <dd>Returns the Nth element in the array, starting at 0.</dd> | |
1090 | <dt><a href='#cupsArrayLast'><code>cupsArrayLast</code></a></dt> | |
1091 | <dd>Returns the last element in the array.</dd> | |
1092 | <dt><a href='#cupsArrayNext'><code>cupsArrayNext</code></a></dt> | |
1093 | <dd>Returns the next element in the array.</dd> | |
1094 | <dt><a href='#cupsArrayPrev'><code>cupsArrayPrev</code></a></dt> | |
1095 | <dd>Returns the previous element in the array.</dd> | |
1096 | </dl> | |
1097 | ||
1098 | <p>Each of these functions returns <code>NULL</code> when there is no | |
1099 | corresponding element. For example, a simple <code>for</code> loop using the | |
1100 | <a href='#cupsArrayFirst'><code>cupsArrayFirst</code></a> and | |
1101 | <a href='#cupsArrayNext'><code>cupsArrayNext</code></a> functions will | |
1102 | enumerate all of the strings in our previous example:</p> | |
1103 | ||
1104 | <pre class='example'> | |
1105 | #include <cups/array.h> | |
1106 | ||
1107 | /* Use strcmp() to compare strings - it will ignore the user_data pointer */ | |
1108 | <a href='#cups_array_t'>cups_array_t</a> *array = <a href='#cupsArrayNew'>cupsArrayNew</a>((<a href='#cups_array_func_t'>cups_array_func_t</a>)strcmp, NULL); | |
1109 | ||
1110 | /* Add four strings to the array */ | |
1111 | <a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "One Fish"); | |
1112 | <a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Two Fish"); | |
1113 | <a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Red Fish"); | |
1114 | <a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Blue Fish"); | |
1115 | ||
1116 | /* Show all of the strings in the array */ | |
1117 | char *s; | |
1118 | for (s = (char *)<a href='#cupsArrayFirst'>cupsArrayFirst</a>(array); s != NULL; s = (char *)<a href='#cupsArrayNext'>cupsArrayNext</a>(array)) | |
1119 | puts(s); | |
1120 | </pre> |