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