2 * Copyright 2002 Red Hat Inc., Durham, North Carolina.
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:
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.
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
30 * Rickard E. (Rik) Faith <faith@redhat.com>
36 * This file provides support routines and helper functions to be used
37 * to pretty-print DMX configurations.
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. */
43 #ifdef HAVE_DMX_CONFIG_H
44 #include <dmx-config.h>
47 #include "dmxconfig.h"
55 static FILE *str
= NULL
;
56 static int indent
= 0;
59 /** Stack of indentation information used for pretty-printing
60 * configuration information. */
66 } *stack
, initialStack
= { 0, 0, 4, NULL
};
68 static void dmxConfigIndent(void)
71 if (indent
< 0) indent
= 0;
72 if (indent
> 40) indent
= 40;
73 for (i
= 0; i
< indent
; i
++) fprintf(str
, " ");
76 static void dmxConfigNewline(void)
78 if (pos
) fprintf(str
, "\n");
82 static void dmxConfigPushState(int base
, int comment
, int step
)
84 struct stack
*new = dmxConfigAlloc(sizeof(*new));
86 new->comment
= comment
;
94 static void dmxConfigPushComment(void)
96 if (stack
) indent
= stack
->comment
;
99 static void dmxConfigPushStep(void)
101 if (stack
) indent
= stack
->step
;
104 static void dmxConfigPopState(void)
106 struct stack
*old
= stack
;
111 if (!stack
) dmxConfigLog("Stack underflow\n");
116 static void dmxConfigOutput(int addSpace
, int doNewline
, const char *comment
,
117 const char *format
, ...)
121 if (!pos
) dmxConfigIndent();
122 else if (addSpace
) fprintf(str
, " ");
125 va_start(args
, format
);
126 /* RATS: This hasn't been audited -- it
127 * could probably result in a buffer
129 pos
+= vfprintf(str
, format
, args
); /* assumes no newlines! */
134 if (pos
) fprintf(str
, " ");
135 pos
+= fprintf(str
, "#%s", comment
);
137 dmxConfigPushComment();
138 } else if (doNewline
) dmxConfigNewline();
141 static void dmxConfigPrintComment(DMXConfigCommentPtr p
)
143 dmxConfigOutput(1, 1, p
->comment
, NULL
);
146 static void dmxConfigPrintTokenFlag(DMXConfigTokenPtr p
, int flag
)
151 dmxConfigPushState(0, 4, 4);
152 dmxConfigOutput(0, 0, p
->comment
, "virtual");
155 dmxConfigPushState(4, 12, 16);
156 dmxConfigOutput(0, 0, p
->comment
, "display");
159 dmxConfigPushState(4, 12, 16);
160 dmxConfigOutput(0, 0, p
->comment
, "wall");
163 dmxConfigPushState(4, 12, 16);
164 dmxConfigOutput(0, 0, p
->comment
, "option");
167 dmxConfigPushState(4, 8, 12);
168 dmxConfigOutput(0, 0, p
->comment
, "param");
171 dmxConfigOutput(0, 1, p
->comment
, ";");
172 if (flag
) dmxConfigPopState();
175 dmxConfigOutput(1, 1, p
->comment
, "{");
179 if (flag
) dmxConfigPopState();
180 dmxConfigOutput(0, 1, p
->comment
, "}");
183 dmxConfigOutput(1, 0, NULL
, "/");
186 dmxConfigLog("unknown token %d on line %d\n", p
->token
, p
->line
);
190 static void dmxConfigPrintToken(DMXConfigTokenPtr p
)
192 dmxConfigPrintTokenFlag(p
, 1);
195 static void dmxConfigPrintTokenNopop(DMXConfigTokenPtr p
)
197 dmxConfigPrintTokenFlag(p
, 0);
200 static int dmxConfigPrintQuotedString(const char *s
)
204 if (!s
|| !s
[0]) return 1; /* Quote empty string */
205 for (pt
= s
; *pt
; ++pt
) if (isspace(*pt
)) return 1;
209 static void dmxConfigPrintString(DMXConfigStringPtr p
, int quote
)
211 DMXConfigStringPtr pt
;
214 for (pt
= p
; pt
; pt
= pt
->next
) {
215 if (quote
&& dmxConfigPrintQuotedString(pt
->string
)) {
216 dmxConfigOutput(1, 0, pt
->comment
, "\"%s\"",
217 pt
->string
? pt
->string
: "");
219 dmxConfigOutput(1, 0, pt
->comment
, "%s",
220 pt
->string
? pt
->string
: "");
224 static int dmxConfigPrintPair(DMXConfigPairPtr p
, int addSpace
)
226 const char *format
= NULL
;
230 case T_ORIGIN
: format
= "@%dx%d"; break;
231 case T_DIMENSION
: format
= "%dx%d"; break;
232 case T_OFFSET
: format
= "%c%d%c%d"; break;
234 if (p
->token
== T_OFFSET
) {
235 if (!p
->comment
&& !p
->x
&& !p
->y
&& p
->xsign
>= 0 && p
->ysign
>= 0)
237 dmxConfigOutput(addSpace
, 0, p
->comment
, format
,
238 p
->xsign
< 0 ? '-' : '+', p
->x
,
239 p
->ysign
< 0 ? '-' : '+', p
->y
);
241 if (!p
->comment
&& !p
->x
&& !p
->y
) return 0;
242 dmxConfigOutput(addSpace
, 0, p
->comment
, format
, p
->x
, p
->y
);
247 static void dmxConfigPrintDisplay(DMXConfigDisplayPtr p
)
249 DMXConfigToken dummyStart
= { T_DISPLAY
, 0, NULL
};
250 DMXConfigToken dummyEnd
= { ';', 0, NULL
};
251 DMXConfigToken dummySep
= { '/', 0, NULL
};
252 DMXConfigString dummyName
= { T_STRING
, 0, NULL
, NULL
, NULL
};
253 DMXConfigPair dummySDim
= { T_DIMENSION
, 0, NULL
, 0, 0, 0, 0 };
254 DMXConfigPair dummySOffset
= { T_OFFSET
, 0, NULL
, 0, 0, 0, 0 };
255 DMXConfigPair dummyRDim
= { T_DIMENSION
, 0, NULL
, 0, 0, 0, 0 };
256 DMXConfigPair dummyROffset
= { T_OFFSET
, 0, NULL
, 0, 0, 0, 0 };
257 DMXConfigPair dummyOrigin
= { T_ORIGIN
, 0, NULL
, 0, 0, 0, 0 };
260 if (p
->dname
) p
->dname
->string
= p
->name
;
261 else dummyName
.string
= p
->name
;
263 if (p
->dim
&& p
->dim
->scrn
&& p
->dim
->scrn
->dim
) {
264 p
->dim
->scrn
->dim
->x
= p
->scrnWidth
;
265 p
->dim
->scrn
->dim
->y
= p
->scrnHeight
;
267 dummySDim
.x
= p
->scrnWidth
;
268 dummySDim
.y
= p
->scrnHeight
;
271 if (p
->dim
&& p
->dim
->scrn
&& p
->dim
->scrn
->offset
) {
272 p
->dim
->scrn
->offset
->x
= p
->scrnX
;
273 p
->dim
->scrn
->offset
->y
= p
->scrnY
;
275 dummySOffset
.x
= p
->scrnX
;
276 dummySOffset
.y
= p
->scrnY
;
279 if (p
->dim
&& p
->dim
->root
&& p
->dim
->root
->dim
) {
280 p
->dim
->root
->dim
->x
= p
->rootWidth
;
281 p
->dim
->root
->dim
->y
= p
->rootHeight
;
283 dummyRDim
.x
= p
->rootWidth
;
284 dummyRDim
.y
= p
->rootHeight
;
287 if (p
->dim
&& p
->dim
->root
&& p
->dim
->root
->offset
) {
288 p
->dim
->root
->offset
->x
= p
->rootX
;
289 p
->dim
->root
->offset
->y
= p
->rootY
;
291 dummyROffset
.x
= p
->rootX
;
292 dummyROffset
.y
= p
->rootY
;
296 p
->origin
->x
= p
->rootXOrigin
, p
->origin
->y
= p
->rootYOrigin
;
297 p
->origin
->xsign
= p
->rootXSign
, p
->origin
->ysign
= p
->rootYSign
;
299 dummyOrigin
.x
= p
->rootXOrigin
, dummyOrigin
.y
= p
->rootYOrigin
;
300 dummyOrigin
.xsign
= p
->rootXSign
, dummyOrigin
.ysign
= p
->rootYSign
;
303 dmxConfigPrintToken(p
->start
? p
->start
: &dummyStart
);
304 dmxConfigPrintString(p
->dname
? p
->dname
: &dummyName
, 1);
306 if (p
->dim
&& p
->dim
->scrn
&& p
->dim
->scrn
->dim
)
307 output
= dmxConfigPrintPair(p
->dim
->scrn
->dim
, 1);
309 output
= dmxConfigPrintPair(&dummySDim
, 1);
310 if (p
->dim
&& p
->dim
->scrn
&& p
->dim
->scrn
->offset
)
311 dmxConfigPrintPair(p
->dim
->scrn
->offset
, !output
);
313 dmxConfigPrintPair(&dummySOffset
, !output
);
315 if (p
->scrnWidth
!= p
->rootWidth
316 || p
->scrnHeight
!= p
->rootHeight
319 dmxConfigPrintToken(&dummySep
);
320 if (p
->dim
&& p
->dim
->root
&& p
->dim
->root
->dim
)
321 output
= dmxConfigPrintPair(p
->dim
->root
->dim
, 1);
323 output
= dmxConfigPrintPair(&dummyRDim
, 1);
324 if (p
->dim
&& p
->dim
->root
&& p
->dim
->root
->offset
)
325 dmxConfigPrintPair(p
->dim
->root
->offset
, !output
);
327 dmxConfigPrintPair(&dummyROffset
, !output
);
330 dmxConfigPrintPair(p
->origin
? p
->origin
: &dummyOrigin
, 1);
331 dmxConfigPrintToken(p
->end
? p
->end
: &dummyEnd
);
334 static void dmxConfigPrintWall(DMXConfigWallPtr p
)
336 dmxConfigPrintToken(p
->start
);
337 dmxConfigPrintPair(p
->wallDim
, 1);
338 dmxConfigPrintPair(p
->displayDim
, 1);
339 dmxConfigPrintString(p
->nameList
, 1);
340 dmxConfigPrintToken(p
->end
);
343 static void dmxConfigPrintOption(DMXConfigOptionPtr p
)
345 DMXConfigToken dummyStart
= { T_OPTION
, 0, NULL
};
346 DMXConfigString dummyOption
= { T_STRING
, 0, NULL
, NULL
, NULL
};
347 DMXConfigToken dummyEnd
= { ';', 0, NULL
};
349 dummyOption
.string
= p
->string
;
351 dmxConfigPrintToken(p
->start
? p
->start
: &dummyStart
);
352 dmxConfigPrintString(&dummyOption
, 0);
353 dmxConfigPrintToken(p
->end
? p
->end
: &dummyEnd
);
356 static void dmxConfigPrintParam(DMXConfigParamPtr p
)
360 if (p
->open
&& p
->close
) {
361 dmxConfigPrintToken(p
->start
);
362 dmxConfigPrintToken(p
->open
);
363 dmxConfigPrintParam(p
->next
);
364 dmxConfigPrintToken(p
->close
);
365 } else if (p
->end
&& p
->param
) {
366 dmxConfigPrintToken(p
->start
);
367 dmxConfigPrintString(p
->param
, 1);
368 dmxConfigPrintToken(p
->end
);
370 dmxConfigLog("dmxConfigPrintParam: cannot handle format (a)\n");
371 } else if (p
->end
&& p
->param
) {
372 dmxConfigPrintString(p
->param
, 1);
373 dmxConfigPrintTokenNopop(p
->end
);
374 dmxConfigPrintParam(p
->next
);
376 dmxConfigLog("dmxConfigPrintParam: cannot handle format (b)\n");
379 static void dmxConfigPrintSub(DMXConfigSubPtr p
)
384 for (pt
= p
; pt
; pt
= pt
->next
) {
386 case dmxConfigComment
: dmxConfigPrintComment(pt
->comment
); break;
387 case dmxConfigDisplay
: dmxConfigPrintDisplay(pt
->display
); break;
388 case dmxConfigWall
: dmxConfigPrintWall(pt
->wall
); break;
389 case dmxConfigOption
: dmxConfigPrintOption(pt
->option
); break;
390 case dmxConfigParam
: dmxConfigPrintParam(pt
->param
); break;
392 dmxConfigLog("dmxConfigPrintSub:"
393 " cannot handle type %d in subentry\n", pt
->type
);
398 static void dmxConfigPrintVirtual(DMXConfigVirtualPtr p
)
400 DMXConfigToken dummyStart
= { T_VIRTUAL
, 0, NULL
};
401 DMXConfigToken dummyOpen
= { '{', 0, NULL
};
402 DMXConfigToken dummyClose
= { '}', 0, NULL
};
403 DMXConfigString dummyName
= { T_STRING
, 0, NULL
, NULL
, NULL
};
404 DMXConfigPair dummyDim
= { T_DIMENSION
, 0, NULL
, 0, 0 };
406 if (p
->vname
) p
->vname
->string
= p
->name
;
407 else dummyName
.string
= p
->name
;
409 if (p
->dim
) p
->dim
->x
= p
->width
, p
->dim
->y
= p
->height
;
410 else dummyDim
.x
= p
->width
, dummyDim
.y
= p
->height
;
413 dmxConfigPrintToken(p
->start
? p
->start
: &dummyStart
);
414 dmxConfigPrintString(p
->vname
? p
->vname
: &dummyName
, 1);
415 dmxConfigPrintPair(p
->dim
? p
->dim
: &dummyDim
, 1);
416 dmxConfigPrintToken(p
->open
? p
->open
: &dummyOpen
);
417 dmxConfigPrintSub(p
->subentry
);
418 dmxConfigPrintToken(p
->close
? p
->close
: &dummyClose
);
421 /** The configuration information in \a entry will be pretty-printed to
422 * the \a stream. If \a stream is NULL, then stdout will be used. */
423 void dmxConfigPrint(FILE *stream
, DMXConfigEntryPtr entry
)
425 DMXConfigEntryPtr pt
;
427 if (!stream
) str
= stdout
;
430 stack
= &initialStack
;
432 for (pt
= entry
; pt
; pt
= pt
->next
) {
434 case dmxConfigComment
: dmxConfigPrintComment(pt
->comment
); break;
435 case dmxConfigVirtual
: dmxConfigPrintVirtual(pt
->virtual); break;
437 dmxConfigLog("dmxConfigPrint: cannot handle type %d in entry\n",
441 if (pos
) dmxConfigNewline();
444 /** The configuration information in \a p will be pretty-printed to the
445 * \a stream. If \a stream is NULL, then stdout will be used. */
446 void dmxConfigVirtualPrint(FILE *stream
, DMXConfigVirtualPtr p
)
448 if (!stream
) str
= stdout
;
451 stack
= &initialStack
;
453 dmxConfigPrintVirtual(p
);
454 if (pos
) dmxConfigNewline();