xref: /OK3568_Linux_fs/external/xserver/hw/dmx/config/dmxprint.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright 2002 Red Hat Inc., Durham, North Carolina.
3  *
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation on the rights to use, copy, modify, merge,
10  * publish, distribute, sublicense, and/or sell copies of the Software,
11  * and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial
16  * portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
22  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25  * SOFTWARE.
26  */
27 
28 /*
29  * Authors:
30  *   Rickard E. (Rik) Faith <faith@redhat.com>
31  *
32  */
33 
34 /** \file
35  *
36  * This file provides support routines and helper functions to be used
37  * to pretty-print DMX configurations.
38  *
39  * Because the DMX configuration file parsing should be capable of being
40  * used in a stand-alone fashion (i.e., independent from the DMX server
41  * source tree), no dependencies on other DMX routines are made. */
42 
43 #ifdef HAVE_DMX_CONFIG_H
44 #include <dmx-config.h>
45 #endif
46 
47 #include "dmxconfig.h"
48 #include "dmxparse.h"
49 #include "dmxprint.h"
50 #include "parser.h"
51 #include <stdio.h>
52 #include <stdarg.h>
53 #include <ctype.h>
54 
55 static FILE *str = NULL;
56 static int indent = 0;
57 static int pos = 0;
58 
59 /** Stack of indentation information used for pretty-printing
60  * configuration information. */
61 static struct stack {
62     int base;
63     int comment;
64     int step;
65     struct stack *next;
66 } *stack, initialStack = {
67 0, 0, 4, NULL};
68 
69 static void
dmxConfigIndent(void)70 dmxConfigIndent(void)
71 {
72     int i;
73 
74     if (indent < 0)
75         indent = 0;
76     if (indent > 40)
77         indent = 40;
78     for (i = 0; i < indent; i++)
79         fprintf(str, " ");
80 }
81 
82 static void
dmxConfigNewline(void)83 dmxConfigNewline(void)
84 {
85     if (pos)
86         fprintf(str, "\n");
87     pos = 0;
88 }
89 
90 static void
dmxConfigPushState(int base,int comment,int step)91 dmxConfigPushState(int base, int comment, int step)
92 {
93     struct stack *new = dmxConfigAlloc(sizeof(*new));
94 
95     new->base = base;
96     new->comment = comment;
97     new->step = step;
98     new->next = stack;
99     stack = new;
100     indent = base;
101     dmxConfigNewline();
102 }
103 
104 static void
dmxConfigPushComment(void)105 dmxConfigPushComment(void)
106 {
107     if (stack)
108         indent = stack->comment;
109 }
110 
111 static void
dmxConfigPushStep(void)112 dmxConfigPushStep(void)
113 {
114     if (stack)
115         indent = stack->step;
116 }
117 
118 static void
dmxConfigPopState(void)119 dmxConfigPopState(void)
120 {
121     struct stack *old = stack;
122 
123     if (!stack)
124         return;
125     indent = old->base;
126     stack = old->next;
127     if (!stack)
128         dmxConfigLog("Stack underflow\n");
129     dmxConfigFree(old);
130     dmxConfigNewline();
131 }
132 
133 static void _X_ATTRIBUTE_PRINTF(4, 5)
dmxConfigOutput(int addSpace,int doNewline,const char * comment,const char * format,...)134 dmxConfigOutput(int addSpace, int doNewline, const char *comment,
135                 const char *format, ...)
136 {
137     va_list args;
138 
139     if (!pos)
140         dmxConfigIndent();
141     else if (addSpace)
142         fprintf(str, " ");
143 
144     if (format) {
145         va_start(args, format);
146         /* RATS: This hasn't been audited -- it
147          * could probably result in a buffer
148          * overflow. */
149         pos += vfprintf(str, format, args);     /* assumes no newlines! */
150         va_end(args);
151     }
152 
153     if (comment) {
154         if (pos)
155             fprintf(str, " ");
156         pos += fprintf(str, "#%s", comment);
157         dmxConfigNewline();
158         dmxConfigPushComment();
159     }
160     else if (doNewline)
161         dmxConfigNewline();
162 }
163 
164 static void
dmxConfigPrintComment(DMXConfigCommentPtr p)165 dmxConfigPrintComment(DMXConfigCommentPtr p)
166 {
167     dmxConfigOutput(1, 1, p->comment, NULL);
168 }
169 
170 static void
dmxConfigPrintTokenFlag(DMXConfigTokenPtr p,int flag)171 dmxConfigPrintTokenFlag(DMXConfigTokenPtr p, int flag)
172 {
173     if (!p)
174         return;
175     switch (p->token) {
176     case T_VIRTUAL:
177         dmxConfigPushState(0, 4, 4);
178         dmxConfigOutput(0, 0, p->comment, "virtual");
179         break;
180     case T_DISPLAY:
181         dmxConfigPushState(4, 12, 16);
182         dmxConfigOutput(0, 0, p->comment, "display");
183         break;
184     case T_WALL:
185         dmxConfigPushState(4, 12, 16);
186         dmxConfigOutput(0, 0, p->comment, "wall");
187         break;
188     case T_OPTION:
189         dmxConfigPushState(4, 12, 16);
190         dmxConfigOutput(0, 0, p->comment, "option");
191         break;
192     case T_PARAM:
193         dmxConfigPushState(4, 8, 12);
194         dmxConfigOutput(0, 0, p->comment, "param");
195         break;
196     case ';':
197         dmxConfigOutput(0, 1, p->comment, ";");
198         if (flag)
199             dmxConfigPopState();
200         break;
201     case '{':
202         dmxConfigOutput(1, 1, p->comment, "{");
203         dmxConfigPushStep();
204         break;
205     case '}':
206         if (flag)
207             dmxConfigPopState();
208         dmxConfigOutput(0, 1, p->comment, "}");
209         break;
210     case '/':
211         dmxConfigOutput(1, 0, NULL, "/");
212         break;
213     default:
214         dmxConfigLog("unknown token %d on line %d\n", p->token, p->line);
215     }
216 }
217 
218 static void
dmxConfigPrintToken(DMXConfigTokenPtr p)219 dmxConfigPrintToken(DMXConfigTokenPtr p)
220 {
221     dmxConfigPrintTokenFlag(p, 1);
222 }
223 
224 static void
dmxConfigPrintTokenNopop(DMXConfigTokenPtr p)225 dmxConfigPrintTokenNopop(DMXConfigTokenPtr p)
226 {
227     dmxConfigPrintTokenFlag(p, 0);
228 }
229 
230 static int
dmxConfigPrintQuotedString(const char * s)231 dmxConfigPrintQuotedString(const char *s)
232 {
233     const char *pt;
234 
235     if (!s || !s[0])
236         return 1;               /* Quote empty string */
237     for (pt = s; *pt; ++pt)
238         if (isspace(*pt))
239             return 1;
240     return 0;
241 }
242 
243 static void
dmxConfigPrintString(DMXConfigStringPtr p,int quote)244 dmxConfigPrintString(DMXConfigStringPtr p, int quote)
245 {
246     DMXConfigStringPtr pt;
247 
248     if (!p)
249         return;
250     for (pt = p; pt; pt = pt->next) {
251         if (quote && dmxConfigPrintQuotedString(pt->string)) {
252             dmxConfigOutput(1, 0, pt->comment, "\"%s\"",
253                             pt->string ? pt->string : "");
254         }
255         else
256             dmxConfigOutput(1, 0, pt->comment, "%s",
257                             pt->string ? pt->string : "");
258     }
259 }
260 
261 static int
dmxConfigPrintPair(DMXConfigPairPtr p,int addSpace)262 dmxConfigPrintPair(DMXConfigPairPtr p, int addSpace)
263 {
264     if (!p)
265         return 0;
266     if (p->token == T_OFFSET) {
267         if (!p->comment && !p->x && !p->y && p->xsign >= 0 && p->ysign >= 0)
268             return 0;
269         dmxConfigOutput(addSpace, 0, p->comment, "%c%d%c%d",
270                         p->xsign < 0 ? '-' : '+', p->x,
271                         p->ysign < 0 ? '-' : '+', p->y);
272     }
273     else {
274         if (!p->comment && !p->x && !p->y)
275             return 0;
276         dmxConfigOutput(addSpace, 0, p->comment, "%s%dx%d",
277                         (p->token == T_ORIGIN) ? "@" : "", p->x, p->y);
278     }
279     return 1;
280 }
281 
282 static void
dmxConfigPrintDisplay(DMXConfigDisplayPtr p)283 dmxConfigPrintDisplay(DMXConfigDisplayPtr p)
284 {
285     DMXConfigToken dummyStart = { T_DISPLAY, 0, NULL };
286     DMXConfigToken dummyEnd = { ';', 0, NULL };
287     DMXConfigToken dummySep = { '/', 0, NULL };
288     DMXConfigString dummyName = { T_STRING, 0, NULL, NULL, NULL };
289     DMXConfigPair dummySDim = { T_DIMENSION, 0, NULL, 0, 0, 0, 0 };
290     DMXConfigPair dummySOffset = { T_OFFSET, 0, NULL, 0, 0, 0, 0 };
291     DMXConfigPair dummyRDim = { T_DIMENSION, 0, NULL, 0, 0, 0, 0 };
292     DMXConfigPair dummyROffset = { T_OFFSET, 0, NULL, 0, 0, 0, 0 };
293     DMXConfigPair dummyOrigin = { T_ORIGIN, 0, NULL, 0, 0, 0, 0 };
294     int output;
295 
296     if (p->dname)
297         p->dname->string = p->name;
298     else
299         dummyName.string = p->name;
300 
301     if (p->dim && p->dim->scrn && p->dim->scrn->dim) {
302         p->dim->scrn->dim->x = p->scrnWidth;
303         p->dim->scrn->dim->y = p->scrnHeight;
304     }
305     else {
306         dummySDim.x = p->scrnWidth;
307         dummySDim.y = p->scrnHeight;
308     }
309 
310     if (p->dim && p->dim->scrn && p->dim->scrn->offset) {
311         p->dim->scrn->offset->x = p->scrnX;
312         p->dim->scrn->offset->y = p->scrnY;
313     }
314     else {
315         dummySOffset.x = p->scrnX;
316         dummySOffset.y = p->scrnY;
317     }
318 
319     if (p->dim && p->dim->root && p->dim->root->dim) {
320         p->dim->root->dim->x = p->rootWidth;
321         p->dim->root->dim->y = p->rootHeight;
322     }
323     else {
324         dummyRDim.x = p->rootWidth;
325         dummyRDim.y = p->rootHeight;
326     }
327 
328     if (p->dim && p->dim->root && p->dim->root->offset) {
329         p->dim->root->offset->x = p->rootX;
330         p->dim->root->offset->y = p->rootY;
331     }
332     else {
333         dummyROffset.x = p->rootX;
334         dummyROffset.y = p->rootY;
335     }
336 
337     if (p->origin) {
338         p->origin->x = p->rootXOrigin, p->origin->y = p->rootYOrigin;
339         p->origin->xsign = p->rootXSign, p->origin->ysign = p->rootYSign;
340     }
341     else {
342         dummyOrigin.x = p->rootXOrigin, dummyOrigin.y = p->rootYOrigin;
343         dummyOrigin.xsign = p->rootXSign, dummyOrigin.ysign = p->rootYSign;
344     }
345 
346     dmxConfigPrintToken(p->start ? p->start : &dummyStart);
347     dmxConfigPrintString(p->dname ? p->dname : &dummyName, 1);
348 
349     if (p->dim && p->dim->scrn && p->dim->scrn->dim)
350         output = dmxConfigPrintPair(p->dim->scrn->dim, 1);
351     else
352         output = dmxConfigPrintPair(&dummySDim, 1);
353     if (p->dim && p->dim->scrn && p->dim->scrn->offset)
354         dmxConfigPrintPair(p->dim->scrn->offset, !output);
355     else
356         dmxConfigPrintPair(&dummySOffset, !output);
357 
358     if (p->scrnWidth != p->rootWidth
359         || p->scrnHeight != p->rootHeight || p->rootX || p->rootY) {
360         dmxConfigPrintToken(&dummySep);
361         if (p->dim && p->dim->root && p->dim->root->dim)
362             output = dmxConfigPrintPair(p->dim->root->dim, 1);
363         else
364             output = dmxConfigPrintPair(&dummyRDim, 1);
365         if (p->dim && p->dim->root && p->dim->root->offset)
366             dmxConfigPrintPair(p->dim->root->offset, !output);
367         else
368             dmxConfigPrintPair(&dummyROffset, !output);
369     }
370 
371     dmxConfigPrintPair(p->origin ? p->origin : &dummyOrigin, 1);
372     dmxConfigPrintToken(p->end ? p->end : &dummyEnd);
373 }
374 
375 static void
dmxConfigPrintWall(DMXConfigWallPtr p)376 dmxConfigPrintWall(DMXConfigWallPtr p)
377 {
378     dmxConfigPrintToken(p->start);
379     dmxConfigPrintPair(p->wallDim, 1);
380     dmxConfigPrintPair(p->displayDim, 1);
381     dmxConfigPrintString(p->nameList, 1);
382     dmxConfigPrintToken(p->end);
383 }
384 
385 static void
dmxConfigPrintOption(DMXConfigOptionPtr p)386 dmxConfigPrintOption(DMXConfigOptionPtr p)
387 {
388     DMXConfigToken dummyStart = { T_OPTION, 0, NULL };
389     DMXConfigString dummyOption = { T_STRING, 0, NULL, NULL, NULL };
390     DMXConfigToken dummyEnd = { ';', 0, NULL };
391 
392     dummyOption.string = p->string;
393 
394     dmxConfigPrintToken(p->start ? p->start : &dummyStart);
395     dmxConfigPrintString(&dummyOption, 0);
396     dmxConfigPrintToken(p->end ? p->end : &dummyEnd);
397 }
398 
399 static void
dmxConfigPrintParam(DMXConfigParamPtr p)400 dmxConfigPrintParam(DMXConfigParamPtr p)
401 {
402     if (!p)
403         return;
404     if (p->start) {
405         if (p->open && p->close) {
406             dmxConfigPrintToken(p->start);
407             dmxConfigPrintToken(p->open);
408             dmxConfigPrintParam(p->next);
409             dmxConfigPrintToken(p->close);
410         }
411         else if (p->end && p->param) {
412             dmxConfigPrintToken(p->start);
413             dmxConfigPrintString(p->param, 1);
414             dmxConfigPrintToken(p->end);
415         }
416         else
417             dmxConfigLog("dmxConfigPrintParam: cannot handle format (a)\n");
418     }
419     else if (p->end && p->param) {
420         dmxConfigPrintString(p->param, 1);
421         dmxConfigPrintTokenNopop(p->end);
422         dmxConfigPrintParam(p->next);
423     }
424     else
425         dmxConfigLog("dmxConfigPrintParam: cannot handle format (b)\n");
426 }
427 
428 static void
dmxConfigPrintSub(DMXConfigSubPtr p)429 dmxConfigPrintSub(DMXConfigSubPtr p)
430 {
431     DMXConfigSubPtr pt;
432 
433     if (!p)
434         return;
435     for (pt = p; pt; pt = pt->next) {
436         switch (pt->type) {
437         case dmxConfigComment:
438             dmxConfigPrintComment(pt->comment);
439             break;
440         case dmxConfigDisplay:
441             dmxConfigPrintDisplay(pt->display);
442             break;
443         case dmxConfigWall:
444             dmxConfigPrintWall(pt->wall);
445             break;
446         case dmxConfigOption:
447             dmxConfigPrintOption(pt->option);
448             break;
449         case dmxConfigParam:
450             dmxConfigPrintParam(pt->param);
451             break;
452         default:
453             dmxConfigLog("dmxConfigPrintSub:"
454                          " cannot handle type %d in subentry\n", pt->type);
455         }
456     }
457 }
458 
459 static void
dmxConfigPrintVirtual(DMXConfigVirtualPtr p)460 dmxConfigPrintVirtual(DMXConfigVirtualPtr p)
461 {
462     DMXConfigToken dummyStart = { T_VIRTUAL, 0, NULL };
463     DMXConfigToken dummyOpen = { '{', 0, NULL };
464     DMXConfigToken dummyClose = { '}', 0, NULL };
465     DMXConfigString dummyName = { T_STRING, 0, NULL, NULL, NULL };
466     DMXConfigPair dummyDim = { T_DIMENSION, 0, NULL, 0, 0 };
467 
468     if (p->vname)
469         p->vname->string = p->name;
470     else
471         dummyName.string = p->name;
472 
473     if (p->dim)
474         p->dim->x = p->width, p->dim->y = p->height;
475     else
476         dummyDim.x = p->width, dummyDim.y = p->height;
477 
478     dmxConfigPrintToken(p->start ? p->start : &dummyStart);
479     dmxConfigPrintString(p->vname ? p->vname : &dummyName, 1);
480     dmxConfigPrintPair(p->dim ? p->dim : &dummyDim, 1);
481     dmxConfigPrintToken(p->open ? p->open : &dummyOpen);
482     dmxConfigPrintSub(p->subentry);
483     dmxConfigPrintToken(p->close ? p->close : &dummyClose);
484 }
485 
486 /** The configuration information in \a entry will be pretty-printed to
487  * the \a stream.  If \a stream is NULL, then stdout will be used. */
488 void
dmxConfigPrint(FILE * stream,DMXConfigEntryPtr entry)489 dmxConfigPrint(FILE * stream, DMXConfigEntryPtr entry)
490 {
491     DMXConfigEntryPtr pt;
492 
493     if (!stream)
494         str = stdout;
495     else
496         str = stream;
497 
498     stack = &initialStack;
499 
500     for (pt = entry; pt; pt = pt->next) {
501         switch (pt->type) {
502         case dmxConfigComment:
503             dmxConfigPrintComment(pt->comment);
504             break;
505         case dmxConfigVirtual:
506             dmxConfigPrintVirtual(pt->virtual);
507             break;
508         default:
509             dmxConfigLog("dmxConfigPrint: cannot handle type %d in entry\n",
510                          pt->type);
511         }
512     }
513     if (pos)
514         dmxConfigNewline();
515 }
516 
517 /** The configuration information in \a p will be pretty-printed to the
518  * \a stream.  If \a stream is NULL, then stdout will be used. */
519 void
dmxConfigVirtualPrint(FILE * stream,DMXConfigVirtualPtr p)520 dmxConfigVirtualPrint(FILE * stream, DMXConfigVirtualPtr p)
521 {
522     if (!stream)
523         str = stdout;
524     else
525         str = stream;
526 
527     stack = &initialStack;
528 
529     dmxConfigPrintVirtual(p);
530     if (pos)
531         dmxConfigNewline();
532 }
533