1706f2543Smrg/*
2706f2543Smrg * Copyright 2002 Red Hat Inc., Durham, North Carolina.
3706f2543Smrg *
4706f2543Smrg * All Rights Reserved.
5706f2543Smrg *
6706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining
7706f2543Smrg * a copy of this software and associated documentation files (the
8706f2543Smrg * "Software"), to deal in the Software without restriction, including
9706f2543Smrg * without limitation on the rights to use, copy, modify, merge,
10706f2543Smrg * publish, distribute, sublicense, and/or sell copies of the Software,
11706f2543Smrg * and to permit persons to whom the Software is furnished to do so,
12706f2543Smrg * subject to the following conditions:
13706f2543Smrg *
14706f2543Smrg * The above copyright notice and this permission notice (including the
15706f2543Smrg * next paragraph) shall be included in all copies or substantial
16706f2543Smrg * portions of the Software.
17706f2543Smrg *
18706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19706f2543Smrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20706f2543Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21706f2543Smrg * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
22706f2543Smrg * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23706f2543Smrg * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24706f2543Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25706f2543Smrg * SOFTWARE.
26706f2543Smrg */
27706f2543Smrg
28706f2543Smrg/*
29706f2543Smrg * Authors:
30706f2543Smrg *   Rickard E. (Rik) Faith <faith@redhat.com>
31706f2543Smrg *
32706f2543Smrg */
33706f2543Smrg
34706f2543Smrg/** \file
35706f2543Smrg *
36706f2543Smrg * This file provides support routines and helper functions to be used
37706f2543Smrg * to pretty-print DMX configurations.
38706f2543Smrg *
39706f2543Smrg * Because the DMX configuration file parsing should be capable of being
40706f2543Smrg * used in a stand-alone fashion (i.e., independent from the DMX server
41706f2543Smrg * source tree), no dependencies on other DMX routines are made. */
42706f2543Smrg
43706f2543Smrg#ifdef HAVE_DMX_CONFIG_H
44706f2543Smrg#include <dmx-config.h>
45706f2543Smrg#endif
46706f2543Smrg
47706f2543Smrg#include "dmxconfig.h"
48706f2543Smrg#include "dmxparse.h"
49706f2543Smrg#include "dmxprint.h"
50706f2543Smrg#include "parser.h"
51706f2543Smrg#include <stdio.h>
52706f2543Smrg#include <stdarg.h>
53706f2543Smrg#include <ctype.h>
54706f2543Smrg
55706f2543Smrgstatic FILE *str   = NULL;
56706f2543Smrgstatic int  indent = 0;
57706f2543Smrgstatic int  pos    = 0;
58706f2543Smrg
59706f2543Smrg/** Stack of indentation information used for pretty-printing
60706f2543Smrg * configuration information. */
61706f2543Smrgstatic struct stack {
62706f2543Smrg    int          base;
63706f2543Smrg    int          comment;
64706f2543Smrg    int          step;
65706f2543Smrg    struct stack *next;
66706f2543Smrg} *stack, initialStack = { 0, 0, 4, NULL };
67706f2543Smrg
68706f2543Smrgstatic void dmxConfigIndent(void)
69706f2543Smrg{
70706f2543Smrg    int i;
71706f2543Smrg    if (indent < 0)  indent = 0;
72706f2543Smrg    if (indent > 40) indent = 40;
73706f2543Smrg    for (i = 0; i < indent; i++) fprintf(str, " ");
74706f2543Smrg}
75706f2543Smrg
76706f2543Smrgstatic void dmxConfigNewline(void)
77706f2543Smrg{
78706f2543Smrg    if (pos) fprintf(str, "\n");
79706f2543Smrg    pos = 0;
80706f2543Smrg}
81706f2543Smrg
82706f2543Smrgstatic void dmxConfigPushState(int base, int comment, int step)
83706f2543Smrg{
84706f2543Smrg    struct stack *new = dmxConfigAlloc(sizeof(*new));
85706f2543Smrg    new->base    = base;
86706f2543Smrg    new->comment = comment;
87706f2543Smrg    new->step    = step;
88706f2543Smrg    new->next    = stack;
89706f2543Smrg    stack        = new;
90706f2543Smrg    indent       = base;
91706f2543Smrg    dmxConfigNewline();
92706f2543Smrg}
93706f2543Smrg
94706f2543Smrgstatic void dmxConfigPushComment(void)
95706f2543Smrg{
96706f2543Smrg    if (stack) indent = stack->comment;
97706f2543Smrg}
98706f2543Smrg
99706f2543Smrgstatic void dmxConfigPushStep(void)
100706f2543Smrg{
101706f2543Smrg    if (stack) indent = stack->step;
102706f2543Smrg}
103706f2543Smrg
104706f2543Smrgstatic void dmxConfigPopState(void)
105706f2543Smrg{
106706f2543Smrg    struct stack *old = stack;
107706f2543Smrg
108706f2543Smrg    if (!stack) return;
109706f2543Smrg    indent = old->base;
110706f2543Smrg    stack  = old->next;
111706f2543Smrg    if (!stack) dmxConfigLog("Stack underflow\n");
112706f2543Smrg    dmxConfigFree(old);
113706f2543Smrg    dmxConfigNewline();
114706f2543Smrg}
115706f2543Smrg
116706f2543Smrgstatic void dmxConfigOutput(int addSpace, int doNewline, const char *comment,
117706f2543Smrg                            const char *format, ...)
118706f2543Smrg{
119706f2543Smrg    va_list args;
120706f2543Smrg
121706f2543Smrg    if (!pos) dmxConfigIndent();
122706f2543Smrg    else if (addSpace) fprintf(str, " ");
123706f2543Smrg
124706f2543Smrg    if (format) {
125706f2543Smrg        va_start(args, format);
126706f2543Smrg                                /* RATS: This hasn't been audited -- it
127706f2543Smrg                                 * could probably result in a buffer
128706f2543Smrg                                 * overflow. */
129706f2543Smrg        pos += vfprintf(str, format, args); /* assumes no newlines! */
130706f2543Smrg        va_end(args);
131706f2543Smrg    }
132706f2543Smrg
133706f2543Smrg    if (comment) {
134706f2543Smrg        if (pos) fprintf(str, " ");
135706f2543Smrg        pos += fprintf(str, "#%s", comment);
136706f2543Smrg        dmxConfigNewline();
137706f2543Smrg        dmxConfigPushComment();
138706f2543Smrg    } else if (doNewline) dmxConfigNewline();
139706f2543Smrg}
140706f2543Smrg
141706f2543Smrgstatic void dmxConfigPrintComment(DMXConfigCommentPtr p)
142706f2543Smrg{
143706f2543Smrg    dmxConfigOutput(1, 1, p->comment, NULL);
144706f2543Smrg}
145706f2543Smrg
146706f2543Smrgstatic void dmxConfigPrintTokenFlag(DMXConfigTokenPtr p, int flag)
147706f2543Smrg{
148706f2543Smrg    if (!p) return;
149706f2543Smrg    switch (p->token) {
150706f2543Smrg    case T_VIRTUAL:
151706f2543Smrg        dmxConfigPushState(0, 4, 4);
152706f2543Smrg        dmxConfigOutput(0, 0, p->comment, "virtual");
153706f2543Smrg        break;
154706f2543Smrg    case T_DISPLAY:
155706f2543Smrg        dmxConfigPushState(4, 12, 16);
156706f2543Smrg        dmxConfigOutput(0, 0, p->comment, "display");
157706f2543Smrg        break;
158706f2543Smrg    case T_WALL:
159706f2543Smrg        dmxConfigPushState(4, 12, 16);
160706f2543Smrg        dmxConfigOutput(0, 0, p->comment, "wall");
161706f2543Smrg        break;
162706f2543Smrg    case T_OPTION:
163706f2543Smrg        dmxConfigPushState(4, 12, 16);
164706f2543Smrg        dmxConfigOutput(0, 0, p->comment, "option");
165706f2543Smrg        break;
166706f2543Smrg    case T_PARAM:
167706f2543Smrg        dmxConfigPushState(4, 8, 12);
168706f2543Smrg        dmxConfigOutput(0, 0, p->comment, "param");
169706f2543Smrg        break;
170706f2543Smrg    case ';':
171706f2543Smrg        dmxConfigOutput(0, 1, p->comment, ";");
172706f2543Smrg        if (flag) dmxConfigPopState();
173706f2543Smrg        break;
174706f2543Smrg    case '{':
175706f2543Smrg        dmxConfigOutput(1, 1, p->comment, "{");
176706f2543Smrg        dmxConfigPushStep();
177706f2543Smrg        break;
178706f2543Smrg    case '}':
179706f2543Smrg        if (flag) dmxConfigPopState();
180706f2543Smrg        dmxConfigOutput(0, 1, p->comment, "}");
181706f2543Smrg        break;
182706f2543Smrg    case '/':
183706f2543Smrg        dmxConfigOutput(1, 0, NULL, "/");
184706f2543Smrg        break;
185706f2543Smrg    default:
186706f2543Smrg        dmxConfigLog("unknown token %d on line %d\n", p->token, p->line);
187706f2543Smrg    }
188706f2543Smrg}
189706f2543Smrg
190706f2543Smrgstatic void dmxConfigPrintToken(DMXConfigTokenPtr p)
191706f2543Smrg{
192706f2543Smrg    dmxConfigPrintTokenFlag(p, 1);
193706f2543Smrg}
194706f2543Smrg
195706f2543Smrgstatic void dmxConfigPrintTokenNopop(DMXConfigTokenPtr p)
196706f2543Smrg{
197706f2543Smrg    dmxConfigPrintTokenFlag(p, 0);
198706f2543Smrg}
199706f2543Smrg
200706f2543Smrgstatic int dmxConfigPrintQuotedString(const char *s)
201706f2543Smrg{
202706f2543Smrg    const char *pt;
203706f2543Smrg
204706f2543Smrg    if (!s || !s[0]) return 1;  /* Quote empty string */
205706f2543Smrg    for (pt = s; *pt; ++pt) if (isspace(*pt)) return 1;
206706f2543Smrg    return 0;
207706f2543Smrg}
208706f2543Smrg
209706f2543Smrgstatic void dmxConfigPrintString(DMXConfigStringPtr p, int quote)
210706f2543Smrg{
211706f2543Smrg    DMXConfigStringPtr pt;
212706f2543Smrg
213706f2543Smrg    if (!p) return;
214706f2543Smrg    for (pt = p; pt; pt = pt->next) {
215706f2543Smrg        if (quote && dmxConfigPrintQuotedString(pt->string)) {
216706f2543Smrg            dmxConfigOutput(1, 0, pt->comment, "\"%s\"",
217706f2543Smrg                            pt->string ? pt->string : "");
218706f2543Smrg            } else
219706f2543Smrg            dmxConfigOutput(1, 0, pt->comment, "%s",
220706f2543Smrg                            pt->string ? pt->string : "");
221706f2543Smrg    }
222706f2543Smrg}
223706f2543Smrg
224706f2543Smrgstatic int dmxConfigPrintPair(DMXConfigPairPtr p, int addSpace)
225706f2543Smrg{
226706f2543Smrg    const char *format = NULL;
227706f2543Smrg
228706f2543Smrg    if (!p) return 0;
229706f2543Smrg    switch (p->token) {
230706f2543Smrg    case T_ORIGIN:    format = "@%dx%d";   break;
231706f2543Smrg    case T_DIMENSION: format = "%dx%d";    break;
232706f2543Smrg    case T_OFFSET:    format = "%c%d%c%d"; break;
233706f2543Smrg    }
234706f2543Smrg    if (p->token == T_OFFSET) {
235706f2543Smrg        if (!p->comment && !p->x && !p->y && p->xsign >= 0 && p->ysign >= 0)
236706f2543Smrg            return 0;
237706f2543Smrg        dmxConfigOutput(addSpace, 0, p->comment, format,
238706f2543Smrg                        p->xsign < 0 ? '-' : '+', p->x,
239706f2543Smrg                        p->ysign < 0 ? '-' : '+', p->y);
240706f2543Smrg    } else {
241706f2543Smrg        if (!p->comment && !p->x && !p->y) return 0;
242706f2543Smrg        dmxConfigOutput(addSpace, 0, p->comment, format, p->x, p->y);
243706f2543Smrg    }
244706f2543Smrg    return 1;
245706f2543Smrg}
246706f2543Smrg
247706f2543Smrgstatic void dmxConfigPrintDisplay(DMXConfigDisplayPtr p)
248706f2543Smrg{
249706f2543Smrg    DMXConfigToken  dummyStart   = { T_DISPLAY, 0, NULL };
250706f2543Smrg    DMXConfigToken  dummyEnd     = { ';', 0, NULL };
251706f2543Smrg    DMXConfigToken  dummySep     = { '/', 0, NULL };
252706f2543Smrg    DMXConfigString dummyName    = { T_STRING, 0, NULL, NULL, NULL };
253706f2543Smrg    DMXConfigPair   dummySDim    = { T_DIMENSION, 0, NULL, 0, 0, 0, 0 };
254706f2543Smrg    DMXConfigPair   dummySOffset = { T_OFFSET, 0, NULL, 0, 0, 0, 0 };
255706f2543Smrg    DMXConfigPair   dummyRDim    = { T_DIMENSION, 0, NULL, 0, 0, 0, 0 };
256706f2543Smrg    DMXConfigPair   dummyROffset = { T_OFFSET, 0, NULL, 0, 0, 0, 0 };
257706f2543Smrg    DMXConfigPair   dummyOrigin  = { T_ORIGIN, 0, NULL, 0, 0, 0, 0 };
258706f2543Smrg    int             output;
259706f2543Smrg
260706f2543Smrg    if (p->dname) p->dname->string = p->name;
261706f2543Smrg    else          dummyName.string = p->name;
262706f2543Smrg
263706f2543Smrg    if (p->dim && p->dim->scrn && p->dim->scrn->dim) {
264706f2543Smrg        p->dim->scrn->dim->x    = p->scrnWidth;
265706f2543Smrg        p->dim->scrn->dim->y    = p->scrnHeight;
266706f2543Smrg    } else {
267706f2543Smrg        dummySDim.x             = p->scrnWidth;
268706f2543Smrg        dummySDim.y             = p->scrnHeight;
269706f2543Smrg    }
270706f2543Smrg
271706f2543Smrg    if (p->dim && p->dim->scrn && p->dim->scrn->offset) {
272706f2543Smrg        p->dim->scrn->offset->x = p->scrnX;
273706f2543Smrg        p->dim->scrn->offset->y = p->scrnY;
274706f2543Smrg    } else {
275706f2543Smrg        dummySOffset.x          = p->scrnX;
276706f2543Smrg        dummySOffset.y          = p->scrnY;
277706f2543Smrg    }
278706f2543Smrg
279706f2543Smrg    if (p->dim && p->dim->root && p->dim->root->dim) {
280706f2543Smrg        p->dim->root->dim->x    = p->rootWidth;
281706f2543Smrg        p->dim->root->dim->y    = p->rootHeight;
282706f2543Smrg    } else {
283706f2543Smrg        dummyRDim.x             = p->rootWidth;
284706f2543Smrg        dummyRDim.y             = p->rootHeight;
285706f2543Smrg    }
286706f2543Smrg
287706f2543Smrg    if (p->dim && p->dim->root && p->dim->root->offset) {
288706f2543Smrg        p->dim->root->offset->x = p->rootX;
289706f2543Smrg        p->dim->root->offset->y = p->rootY;
290706f2543Smrg    } else {
291706f2543Smrg        dummyROffset.x          = p->rootX;
292706f2543Smrg        dummyROffset.y          = p->rootY;
293706f2543Smrg    }
294706f2543Smrg
295706f2543Smrg    if (p->origin) {
296706f2543Smrg        p->origin->x     = p->rootXOrigin, p->origin->y     = p->rootYOrigin;
297706f2543Smrg        p->origin->xsign = p->rootXSign,   p->origin->ysign = p->rootYSign;
298706f2543Smrg    } else {
299706f2543Smrg        dummyOrigin.x     = p->rootXOrigin, dummyOrigin.y     = p->rootYOrigin;
300706f2543Smrg        dummyOrigin.xsign = p->rootXSign,   dummyOrigin.ysign = p->rootYSign;
301706f2543Smrg    }
302706f2543Smrg
303706f2543Smrg    dmxConfigPrintToken(p->start ? p->start : &dummyStart);
304706f2543Smrg    dmxConfigPrintString(p->dname ? p->dname : &dummyName, 1);
305706f2543Smrg
306706f2543Smrg    if (p->dim && p->dim->scrn && p->dim->scrn->dim)
307706f2543Smrg        output = dmxConfigPrintPair(p->dim->scrn->dim, 1);
308706f2543Smrg    else
309706f2543Smrg        output = dmxConfigPrintPair(&dummySDim, 1);
310706f2543Smrg    if (p->dim && p->dim->scrn && p->dim->scrn->offset)
311706f2543Smrg        dmxConfigPrintPair(p->dim->scrn->offset, !output);
312706f2543Smrg    else
313706f2543Smrg        dmxConfigPrintPair(&dummySOffset, !output);
314706f2543Smrg
315706f2543Smrg    if (p->scrnWidth != p->rootWidth
316706f2543Smrg        || p->scrnHeight != p->rootHeight
317706f2543Smrg        || p->rootX
318706f2543Smrg        || p->rootY) {
319706f2543Smrg        dmxConfigPrintToken(&dummySep);
320706f2543Smrg        if (p->dim && p->dim->root && p->dim->root->dim)
321706f2543Smrg            output = dmxConfigPrintPair(p->dim->root->dim, 1);
322706f2543Smrg        else
323706f2543Smrg            output = dmxConfigPrintPair(&dummyRDim, 1);
324706f2543Smrg        if (p->dim && p->dim->root && p->dim->root->offset)
325706f2543Smrg            dmxConfigPrintPair(p->dim->root->offset, !output);
326706f2543Smrg        else
327706f2543Smrg            dmxConfigPrintPair(&dummyROffset, !output);
328706f2543Smrg    }
329706f2543Smrg
330706f2543Smrg    dmxConfigPrintPair(p->origin ? p->origin : &dummyOrigin, 1);
331706f2543Smrg    dmxConfigPrintToken(p->end ? p->end : &dummyEnd);
332706f2543Smrg}
333706f2543Smrg
334706f2543Smrgstatic void dmxConfigPrintWall(DMXConfigWallPtr p)
335706f2543Smrg{
336706f2543Smrg    dmxConfigPrintToken(p->start);
337706f2543Smrg    dmxConfigPrintPair(p->wallDim, 1);
338706f2543Smrg    dmxConfigPrintPair(p->displayDim, 1);
339706f2543Smrg    dmxConfigPrintString(p->nameList, 1);
340706f2543Smrg    dmxConfigPrintToken(p->end);
341706f2543Smrg}
342706f2543Smrg
343706f2543Smrgstatic void dmxConfigPrintOption(DMXConfigOptionPtr p)
344706f2543Smrg{
345706f2543Smrg    DMXConfigToken  dummyStart  = { T_OPTION, 0, NULL };
346706f2543Smrg    DMXConfigString dummyOption = { T_STRING, 0, NULL, NULL, NULL };
347706f2543Smrg    DMXConfigToken  dummyEnd    = { ';', 0, NULL };
348706f2543Smrg
349706f2543Smrg    dummyOption.string = p->string;
350706f2543Smrg
351706f2543Smrg    dmxConfigPrintToken(p->start ? p->start : &dummyStart);
352706f2543Smrg    dmxConfigPrintString(&dummyOption, 0);
353706f2543Smrg    dmxConfigPrintToken(p->end ? p->end : &dummyEnd);
354706f2543Smrg}
355706f2543Smrg
356706f2543Smrgstatic void dmxConfigPrintParam(DMXConfigParamPtr p)
357706f2543Smrg{
358706f2543Smrg    if (!p) return;
359706f2543Smrg    if (p->start) {
360706f2543Smrg        if (p->open && p->close) {
361706f2543Smrg            dmxConfigPrintToken(p->start);
362706f2543Smrg            dmxConfigPrintToken(p->open);
363706f2543Smrg            dmxConfigPrintParam(p->next);
364706f2543Smrg            dmxConfigPrintToken(p->close);
365706f2543Smrg        } else if (p->end && p->param) {
366706f2543Smrg            dmxConfigPrintToken(p->start);
367706f2543Smrg            dmxConfigPrintString(p->param, 1);
368706f2543Smrg            dmxConfigPrintToken(p->end);
369706f2543Smrg        } else
370706f2543Smrg            dmxConfigLog("dmxConfigPrintParam: cannot handle format (a)\n");
371706f2543Smrg    } else if (p->end && p->param) {
372706f2543Smrg        dmxConfigPrintString(p->param, 1);
373706f2543Smrg        dmxConfigPrintTokenNopop(p->end);
374706f2543Smrg        dmxConfigPrintParam(p->next);
375706f2543Smrg    } else
376706f2543Smrg        dmxConfigLog("dmxConfigPrintParam: cannot handle format (b)\n");
377706f2543Smrg}
378706f2543Smrg
379706f2543Smrgstatic void dmxConfigPrintSub(DMXConfigSubPtr p)
380706f2543Smrg{
381706f2543Smrg    DMXConfigSubPtr pt;
382706f2543Smrg
383706f2543Smrg    if (!p) return;
384706f2543Smrg    for (pt = p; pt; pt = pt->next) {
385706f2543Smrg        switch (pt->type) {
386706f2543Smrg        case dmxConfigComment: dmxConfigPrintComment(pt->comment); break;
387706f2543Smrg        case dmxConfigDisplay: dmxConfigPrintDisplay(pt->display); break;
388706f2543Smrg        case dmxConfigWall:    dmxConfigPrintWall(pt->wall);       break;
389706f2543Smrg        case dmxConfigOption:  dmxConfigPrintOption(pt->option);   break;
390706f2543Smrg        case dmxConfigParam:   dmxConfigPrintParam(pt->param);     break;
391706f2543Smrg        default:
392706f2543Smrg            dmxConfigLog("dmxConfigPrintSub:"
393706f2543Smrg                         " cannot handle type %d in subentry\n", pt->type);
394706f2543Smrg        }
395706f2543Smrg    }
396706f2543Smrg}
397706f2543Smrg
398706f2543Smrgstatic void dmxConfigPrintVirtual(DMXConfigVirtualPtr p)
399706f2543Smrg{
400706f2543Smrg    DMXConfigToken  dummyStart = { T_VIRTUAL, 0, NULL };
401706f2543Smrg    DMXConfigToken  dummyOpen  = { '{', 0, NULL };
402706f2543Smrg    DMXConfigToken  dummyClose = { '}', 0, NULL };
403706f2543Smrg    DMXConfigString dummyName  = { T_STRING, 0, NULL, NULL, NULL };
404706f2543Smrg    DMXConfigPair   dummyDim   = { T_DIMENSION, 0, NULL, 0, 0 };
405706f2543Smrg
406706f2543Smrg    if (p->vname) p->vname->string = p->name;
407706f2543Smrg    else          dummyName.string = p->name;
408706f2543Smrg
409706f2543Smrg    if (p->dim) p->dim->x  = p->width, p->dim->y  = p->height;
410706f2543Smrg    else        dummyDim.x = p->width, dummyDim.y = p->height;
411706f2543Smrg
412706f2543Smrg
413706f2543Smrg    dmxConfigPrintToken(p->start ? p->start : &dummyStart);
414706f2543Smrg    dmxConfigPrintString(p->vname ? p->vname : &dummyName, 1);
415706f2543Smrg    dmxConfigPrintPair(p->dim ? p->dim : &dummyDim, 1);
416706f2543Smrg    dmxConfigPrintToken(p->open ? p->open : &dummyOpen);
417706f2543Smrg    dmxConfigPrintSub(p->subentry);
418706f2543Smrg    dmxConfigPrintToken(p->close ? p->close : &dummyClose);
419706f2543Smrg}
420706f2543Smrg
421706f2543Smrg/** The configuration information in \a entry will be pretty-printed to
422706f2543Smrg * the \a stream.  If \a stream is NULL, then stdout will be used. */
423706f2543Smrgvoid dmxConfigPrint(FILE *stream, DMXConfigEntryPtr entry)
424706f2543Smrg{
425706f2543Smrg    DMXConfigEntryPtr pt;
426706f2543Smrg
427706f2543Smrg    if (!stream) str = stdout;
428706f2543Smrg    else         str = stream;
429706f2543Smrg
430706f2543Smrg    stack = &initialStack;
431706f2543Smrg
432706f2543Smrg    for (pt = entry; pt; pt = pt->next) {
433706f2543Smrg        switch (pt->type) {
434706f2543Smrg        case dmxConfigComment: dmxConfigPrintComment(pt->comment); break;
435706f2543Smrg        case dmxConfigVirtual: dmxConfigPrintVirtual(pt->virtual); break;
436706f2543Smrg        default:
437706f2543Smrg            dmxConfigLog("dmxConfigPrint: cannot handle type %d in entry\n",
438706f2543Smrg                         pt->type);
439706f2543Smrg        }
440706f2543Smrg    }
441706f2543Smrg    if (pos) dmxConfigNewline();
442706f2543Smrg}
443706f2543Smrg
444706f2543Smrg/** The configuration information in \a p will be pretty-printed to the
445706f2543Smrg * \a stream.  If \a stream is NULL, then stdout will be used. */
446706f2543Smrgvoid dmxConfigVirtualPrint(FILE *stream, DMXConfigVirtualPtr p)
447706f2543Smrg{
448706f2543Smrg    if (!stream) str = stdout;
449706f2543Smrg    else         str = stream;
450706f2543Smrg
451706f2543Smrg    stack = &initialStack;
452706f2543Smrg
453706f2543Smrg    dmxConfigPrintVirtual(p);
454706f2543Smrg    if (pos) dmxConfigNewline();
455706f2543Smrg}
456