]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/form-tree.c
Load cups into easysw/current.
[thirdparty/cups.git] / filter / form-tree.c
1 /*
2 * "$Id: form-tree.c 6649 2007-07-11 21:46:42Z mike $"
3 *
4 * CUPS form document tree routines for the Common UNIX Printing
5 * System (CUPS).
6 *
7 * Copyright 2007 by Apple Inc.
8 * Copyright 1997-2005 by Easy Software Products.
9 *
10 * These coded instructions, statements, and computer programs are the
11 * property of Apple Inc. and are protected by Federal copyright
12 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
13 * which should have been included with this file. If this file is
14 * file is missing or damaged, see the license at "http://www.cups.org/".
15 *
16 * This file is subject to the Apple OS-Developed Software exception.
17 *
18 * Contents:
19 *
20 */
21
22 /*
23 * Include necessary headers...
24 */
25
26 #include "form.h"
27
28
29 /*
30 * Local functions...
31 */
32
33 static int compare_attr(attr_t *a0, attr_t *a1);
34 static int compare_elements(char **e0, char **e1);
35 static int parse_attr(tree_t *t, FILE *fp);
36 static int parse_element(tree_t *t, FILE *fp);
37
38
39 /*
40 * Local globals...
41 */
42
43 static char *elements[] =
44 {
45 "",
46 "!--",
47 "ARC",
48 "BOX",
49 "BR",
50 "B",
51 "CUPSFORM",
52 "DEFVAR",
53 "FONT",
54 "H1",
55 "H2",
56 "H3",
57 "H4",
58 "H5",
59 "H6",
60 "HEAD",
61 "IMG",
62 "I",
63 "LINE",
64 "PAGE",
65 "PIE",
66 "POLY",
67 "PRE",
68 "P",
69 "RECT",
70 "TEXT",
71 "TT",
72 "VAR"
73 };
74
75
76 /*
77 * 'formDelete()' - Delete a node and its children.
78 */
79
80 void
81 formDelete(tree_t *t) /* I - Tree node */
82 {
83 }
84
85
86 /*
87 * 'formGetAttr()' - Get a node attribute value.
88 */
89
90 char * /* O - Value or NULL */
91 formGetAttr(tree_t *t, /* I - Tree node */
92 const char *name) /* I - Name of attribute */
93 {
94 }
95
96
97 /*
98 * 'formNew()' - Create a new form node.
99 */
100
101 tree_t * /* O - New tree node */
102 formNew(tree_t *p) /* I - Parent node */
103 {
104 tree_t *t; /* New tree node */
105
106
107 /*
108 * Allocate the new node...
109 */
110
111 if ((t = (tree_t *)calloc(sizeof(tree_t), 1)) == NULL)
112 return (NULL);
113
114 /*
115 * Set/copy attributes...
116 */
117
118 if (p == NULL)
119 {
120 t->bg[0] = 1.0;
121 t->bg[1] = 1.0;
122 t->bg[2] = 1.0;
123 t->halign = HALIGN_LEFT;
124 t->valign = VALIGN_MIDDLE;
125 t->typeface = "Courier";
126 t->size = 12.0;
127 }
128 else
129 {
130 memcpy(t, p, sizeof(tree_t));
131
132 t->prev = NULL;
133 t->next = NULL;
134 t->child = NULL;
135 t->last_child = NULL;
136 t->parent = NULL;
137 t->num_attrs = 0;
138 t->attrs = NULL;
139 t->data = NULL;
140 }
141
142 /*
143 * Return the new node...
144 */
145
146 return (t);
147 }
148
149
150 /*
151 * 'formRead()' - Read a form tree from a file.
152 */
153
154 tree_t * /* O - New form tree */
155 formRead(FILE *fp, /* I - File to read from */
156 tree_t *p) /* I - Parent node */
157 {
158 int ch, /* Character from file */
159 closech, /* Closing character */
160 have_whitespace; /* Leading whitespace? */
161 static char s[10240]; /* String from file */
162 uchar *ptr, /* Pointer in string */
163 glyph[16], /* Glyph name (&#nnn;) */
164 *glyphptr; /* Pointer in glyph string */
165 tree_t *tree, /* "top" of this tree */
166 *t, /* New tree node */
167 *prev, /* Previous tree node */
168 *temp; /* Temporary looping var */
169 uchar *face, /* Typeface for FONT tag */
170 *color, /* Color for FONT tag */
171 *size; /* Size for FONT tag */
172
173
174 /*
175 * Start off with no previous tree node...
176 */
177
178 prev = NULL;
179 tree = NULL;
180
181 /*
182 * Parse data until we hit end-of-file...
183 */
184
185 while ((ch = getc(fp)) != EOF)
186 {
187 /*
188 * Ignore leading whitespace...
189 */
190
191 have_whitespace = 0;
192 closech = '/';
193
194 if (p == NULL || !p->preformatted)
195 {
196 while (isspace(ch & 255))
197 {
198 have_whitespace = 1;
199 ch = getc(fp);
200 }
201
202 if (ch == EOF)
203 break;
204 }
205
206 /*
207 * Allocate a new tree node - use calloc() to get zeroed data...
208 */
209
210 t = formNew(p);
211
212 /*
213 * See what the character was...
214 */
215
216 if (ch == '<')
217 {
218 /*
219 * Markup char; grab the next char to see if this is a /...
220 */
221
222 ch = getc(fp);
223 if (ch == ' ')
224 {
225 /*
226 * Illegal lone "<"! Ignore it...
227 */
228
229 free(t);
230 continue;
231 }
232
233 if (ch != '/')
234 ungetc(ch, fp);
235
236 if (parse_element(t, fp) < 0)
237 {
238 free(t);
239 break;
240 }
241
242 if ((closech = getc(fp)) == '/')
243 getc(fp);
244
245 /*
246 * If this is the matching close mark, or if we are starting the same
247 * element, or if we've completed a list, we're done!
248 */
249
250 if (ch == '/')
251 {
252 /*
253 * Close element; find matching element...
254 */
255
256 for (temp = p; temp != NULL; temp = temp->p)
257 if (temp->element == t->element)
258 break;
259
260 free(t);
261
262 if (temp != NULL)
263 break;
264 else
265 continue;
266 }
267 }
268 else if (t->preformatted)
269 {
270 /*
271 * Read a pre-formatted string into the current tree node...
272 */
273
274 ptr = s;
275 while (ch != '<' && ch != EOF && ptr < (s + sizeof(s) - 1))
276 {
277 if (ch == '&')
278 {
279 for (glyphptr = glyph;
280 (ch = getc(fp)) != EOF && (glyphptr - glyph) < 15;
281 glyphptr ++)
282 if (!isalnum(ch & 255))
283 break;
284 else
285 *glyphptr = ch;
286
287 *glyphptr = '\0';
288 if (atoi(glyph) > 0)
289 ch = atoi(glyph);
290 else if (strcmp(glyph, "lt") == 0)
291 ch = '<';
292 else if (strcmp(glyph, "gt") == 0)
293 ch = '>';
294 else if (strcmp(glyph, "quot") == 0)
295 ch = '\'';
296 else if (strcmp(glyph, "nbsp") == 0)
297 ch = ' ';
298 else
299 ch = '&';
300 }
301
302 if (ch != 0)
303 *ptr++ = ch;
304
305 if (ch == '\n')
306 break;
307
308 ch = getc(fp);
309 }
310
311 *ptr = '\0';
312
313 if (ch == '<')
314 ungetc(ch, fp);
315
316 t->element = ELEMENT_FRAGMENT;
317 t->data = strdup(s);
318 }
319 else
320 {
321 /*
322 * Read the next string fragment...
323 */
324
325 ptr = s;
326 if (have_whitespace)
327 *ptr++ = ' ';
328
329 while (!isspace(ch & 255) && ch != '<' && ch != EOF && ptr < (s + sizeof(s) - 1))
330 {
331 if (ch == '&')
332 {
333 for (glyphptr = glyph;
334 (ch = getc(fp)) != EOF && (glyphptr - glyph) < 15;
335 glyphptr ++)
336 if (!isalnum(ch & 255))
337 break;
338 else
339 *glyphptr = ch;
340
341 *glyphptr = '\0';
342 if (atoi(glyph) > 0)
343 ch = atoi(glyph);
344 else if (strcmp(glyph, "lt") == 0)
345 ch = '<';
346 else if (strcmp(glyph, "gt") == 0)
347 ch = '>';
348 else if (strcmp(glyph, "quot") == 0)
349 ch = '\'';
350 else if (strcmp(glyph, "nbsp") == 0)
351 ch = ' ';
352 else
353 ch = '&';
354 }
355
356 if (ch != 0)
357 *ptr++ = ch;
358
359 ch = getc(fp);
360 }
361
362 if (isspace(ch & 255))
363 *ptr++ = ' ';
364
365 *ptr = '\0';
366
367 if (ch == '<')
368 ungetc(ch, fp);
369
370 t->element = ELEMENT_FRAGMENT;
371 t->data = strdup(s);
372 }
373
374 /*
375 * If the p tree pointer is not NULL and this is the first
376 * entry we've read, set the child pointer...
377 */
378
379 if (p != NULL && prev == NULL)
380 p->child = t;
381
382 if (p != NULL)
383 p->last_child = t;
384
385 /*
386 * Do the prev/next links...
387 */
388
389 t->parent = p;
390 t->prev = prev;
391 if (prev != NULL)
392 prev->next = t;
393 else
394 tree = t;
395
396 prev = t;
397
398 /*
399 * Do child stuff as needed...
400 */
401
402 if (closech == '>')
403 t->child = formRead(t, fp);
404 }
405
406 return (tree);
407 }
408
409
410 /*
411 * 'formSetAttr()' - Set a node attribute.
412 */
413
414 void
415 formSetAttr(tree_t *t, /* I - Tree node */
416 const char *name, /* I - Attribute name */
417 const char *value) /* I - Attribute value */
418 {
419 }
420
421
422 /*
423 * 'compare_attr()' - Compare two attributes.
424 */
425
426 static int /* O - -1 if a0 < a1, etc. */
427 compare_attr(attr_t *a0, /* I - First attribute */
428 attr_t *a1) /* I - Second attribute */
429 {
430 return (strcasecmp(a0->name, a1->name));
431 }
432
433
434 /*
435 * 'compare_elements()' - Compare two elements.
436 */
437
438 static int /* O - -1 if e0 < e1, etc. */
439 compare_elements(char **e0, /* I - First element */
440 char **e1) /* I - Second element */
441 {
442 return (strcasecmp(*e0, *e1));
443 }
444
445
446 /*
447 * 'parse_attr()' - Parse an element attribute string.
448 */
449
450 static int /* O - -1 on error, 0 on success */
451 parse_attr(tree_t *t, /* I - Current tree node */
452 FILE *fp) /* I - Input file */
453 {
454 char name[1024], /* Name of attr */
455 value[10240], /* Value of attr */
456 *ptr; /* Temporary pointer */
457 int ch; /* Character from file */
458
459
460 ptr = name;
461 while ((ch = getc(fp)) != EOF)
462 if (isalnum(ch & 255))
463 {
464 if (ptr < (name + sizeof(name) - 1))
465 *ptr++ = ch;
466 }
467 else
468 break;
469
470 *ptr = '\0';
471
472 while (isspace(ch & 255) || ch == '\r')
473 ch = getc(fp);
474
475 switch (ch)
476 {
477 default :
478 ungetc(ch, fp);
479 return (formSetAttr(t, name, NULL));
480 case EOF :
481 return (-1);
482 case '=' :
483 ptr = value;
484 ch = getc(fp);
485
486 while (isspace(ch & 255) || ch == '\r')
487 ch = getc(fp);
488
489 if (ch == EOF)
490 return (-1);
491
492 if (ch == '\'')
493 {
494 while ((ch = getc(fp)) != EOF)
495 if (ch == '\'')
496 break;
497 else if (ptr < (value + sizeof(value) - 1))
498 *ptr++ = ch;
499
500 *ptr = '\0';
501 }
502 else if (ch == '\"')
503 {
504 while ((ch = getc(fp)) != EOF)
505 if (ch == '\"')
506 break;
507 else if (ptr < (value + sizeof(value) - 1))
508 *ptr++ = ch;
509
510 *ptr = '\0';
511 }
512 else
513 {
514 *ptr++ = ch;
515 while ((ch = getc(fp)) != EOF)
516 if (isspace(ch & 255) || ch == '>' || ch == '/' || ch == '\r')
517 break;
518 else if (ptr < (value + sizeof(value) - 1))
519 *ptr++ = ch;
520
521 *ptr = '\0';
522 if (ch == '>' || ch == '/')
523 ungetc(ch, fp);
524 }
525
526 return (formSetAttr(t, name, value));
527 }
528 }
529
530
531 /*
532 * 'parse_element()' - Parse an element.
533 */
534
535 static int /* O - -1 on error or ELEMENT_nnnn */
536 parse_element(tree_t *t, /* I - Current tree node */
537 FILE *fp) /* I - Input file */
538 {
539 int ch; /* Character from file */
540 char element[255], /* Element string... */
541 *eptr, /* Current character... */
542 comment[10240], /* Comment string */
543 *cptr, /* Current char... */
544 **temp; /* Element variable entry */
545
546
547 eptr = element;
548
549 while ((ch = getc(fp)) != EOF && eptr < (element + sizeof(element) - 1))
550 if (ch == '>' || ch == '/' || isspace(ch & 255))
551 break;
552 else
553 *eptr++ = ch;
554
555 *eptr = '\0';
556
557 if (ch == EOF)
558 return (ELEMENT_ERROR);
559
560 eptr = element;
561 temp = bsearch(&mptr, elements, sizeof(elements) / sizeof(elements[0]),
562 sizeof(elements[0]),
563 (int (*)(const void *, const void *))compare_elements);
564
565 if (temp == NULL)
566 {
567 /*
568 * Unrecognized element stuff...
569 */
570
571 t->element = ELEMENT_COMMENT;
572 strcpy(comment, element);
573 cptr = comment + strlen(comment);
574 }
575 else
576 {
577 t->element = (element_t)((char **)temp - elements);
578 cptr = comment;
579 }
580
581 if (t->element == ELEMENT_COMMENT)
582 {
583 while (ch != EOF && ch != '>' && cptr < (comment + sizeof(comment) - 1))
584 {
585 *cptr++ = ch;
586 ch = getc(fp);
587 }
588
589 *cptr = '\0';
590 t->data = strdup(comment);
591 }
592 else
593 {
594 while (ch != EOF && ch != '>' && ch != '/')
595 {
596 if (!isspace(ch & 255))
597 {
598 ungetc(ch, fp);
599 parse_variable(t, fp);
600 }
601
602 ch = getc(fp);
603 }
604
605 if (ch != EOF)
606 ungetc(ch, fp);
607 }
608
609 return (t->element);
610 }
611
612
613 /*
614 * End of "$Id: form-tree.c 6649 2007-07-11 21:46:42Z mike $".
615 */