1/*
2 * Copyright (c) 1997  Metro Link Incorporated
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 *
22 * Except as contained in this notice, the name of the Metro Link shall not be
23 * used in advertising or otherwise to promote the sale, use or other dealings
24 * in this Software without prior written authorization from Metro Link.
25 *
26 */
27/*
28 * Copyright (c) 1997-2003 by The XFree86 Project, Inc.
29 *
30 * Permission is hereby granted, free of charge, to any person obtaining a
31 * copy of this software and associated documentation files (the "Software"),
32 * to deal in the Software without restriction, including without limitation
33 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
34 * and/or sell copies of the Software, and to permit persons to whom the
35 * Software is furnished to do so, subject to the following conditions:
36 *
37 * The above copyright notice and this permission notice shall be included in
38 * all copies or substantial portions of the Software.
39 *
40 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
43 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
44 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
45 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
46 * OTHER DEALINGS IN THE SOFTWARE.
47 *
48 * Except as contained in this notice, the name of the copyright holder(s)
49 * and author(s) shall not be used in advertising or otherwise to promote
50 * the sale, use or other dealings in this Software without prior written
51 * authorization from the copyright holder(s) and author(s).
52 */
53
54
55/* View/edit this file with tab stops set to 4 */
56
57#ifdef HAVE_XORG_CONFIG_H
58#include <xorg-config.h>
59#endif
60
61#include "xf86Parser.h"
62#include "xf86tokens.h"
63#include "Configint.h"
64#include <X11/Xfuncproto.h>
65#include "Xprintf.h"
66
67extern LexRec val;
68
69static xf86ConfigSymTabRec ServerFlagsTab[] =
70{
71	{ENDSECTION, "endsection"},
72	{NOTRAPSIGNALS, "notrapsignals"},
73	{DONTZAP, "dontzap"},
74	{DONTZOOM, "dontzoom"},
75	{DISABLEVIDMODE, "disablevidmodeextension"},
76	{ALLOWNONLOCAL, "allownonlocalxvidtune"},
77	{DISABLEMODINDEV, "disablemodindev"},
78	{MODINDEVALLOWNONLOCAL, "allownonlocalmodindev"},
79	{ALLOWMOUSEOPENFAIL, "allowmouseopenfail"},
80	{OPTION, "option"},
81	{BLANKTIME, "blanktime"},
82	{STANDBYTIME, "standbytime"},
83	{SUSPENDTIME, "suspendtime"},
84	{OFFTIME, "offtime"},
85	{DEFAULTLAYOUT, "defaultserverlayout"},
86	{-1, ""},
87};
88
89#define CLEANUP xf86freeFlags
90
91XF86ConfFlagsPtr
92xf86parseFlagsSection (void)
93{
94	int token;
95	parsePrologue (XF86ConfFlagsPtr, XF86ConfFlagsRec)
96
97	while ((token = xf86getToken (ServerFlagsTab)) != ENDSECTION)
98	{
99		int hasvalue = FALSE;
100		int strvalue = FALSE;
101		int tokentype;
102		switch (token)
103		{
104		case COMMENT:
105			ptr->flg_comment = xf86addComment(ptr->flg_comment, val.str);
106			break;
107			/*
108			 * these old keywords are turned into standard generic options.
109			 * we fall through here on purpose
110			 */
111		case DEFAULTLAYOUT:
112			strvalue = TRUE;
113		case BLANKTIME:
114		case STANDBYTIME:
115		case SUSPENDTIME:
116		case OFFTIME:
117			hasvalue = TRUE;
118		case NOTRAPSIGNALS:
119		case DONTZAP:
120		case DONTZOOM:
121		case DISABLEVIDMODE:
122		case ALLOWNONLOCAL:
123		case DISABLEMODINDEV:
124		case MODINDEVALLOWNONLOCAL:
125		case ALLOWMOUSEOPENFAIL:
126			{
127				int i = 0;
128				while (ServerFlagsTab[i].token != -1)
129				{
130					char *tmp;
131
132					if (ServerFlagsTab[i].token == token)
133					{
134						char *valstr = NULL;
135						tmp = strdup (ServerFlagsTab[i].name);
136						if (hasvalue)
137						{
138							tokentype = xf86getSubToken(&(ptr->flg_comment));
139							if (strvalue) {
140								if (tokentype != STRING)
141									Error (QUOTE_MSG, tmp);
142								valstr = val.str;
143							} else {
144								if (tokentype != NUMBER)
145									Error (NUMBER_MSG, tmp);
146								if (asprintf(&valstr, "%d", val.num) == -1)
147									valstr = NULL;
148							}
149						}
150						ptr->flg_option_lst = xf86addNewOption
151							(ptr->flg_option_lst, tmp, valstr);
152					}
153					i++;
154				}
155			}
156			break;
157		case OPTION:
158			ptr->flg_option_lst = xf86parseOption(ptr->flg_option_lst);
159			break;
160
161		case EOF_TOKEN:
162			Error (UNEXPECTED_EOF_MSG, NULL);
163			break;
164		default:
165			Error (INVALID_KEYWORD_MSG, xf86tokenString ());
166			break;
167		}
168	}
169
170#ifdef DEBUG
171	printf ("Flags section parsed\n");
172#endif
173
174	return ptr;
175}
176
177#undef CLEANUP
178
179void
180xf86printServerFlagsSection (FILE * f, XF86ConfFlagsPtr flags)
181{
182	XF86OptionPtr p;
183
184	if ((!flags) || (!flags->flg_option_lst))
185		return;
186	p = flags->flg_option_lst;
187	fprintf (f, "Section \"ServerFlags\"\n");
188	if (flags->flg_comment)
189		fprintf (f, "%s", flags->flg_comment);
190	xf86printOptionList(f, p, 1);
191	fprintf (f, "EndSection\n\n");
192}
193
194static XF86OptionPtr
195addNewOption2 (XF86OptionPtr head, char *name, char *val, int used)
196{
197	XF86OptionPtr new, old = NULL;
198
199	/* Don't allow duplicates, free old strings */
200	if (head != NULL && (old = xf86findOption(head, name)) != NULL) {
201		new = old;
202		free(new->opt_name);
203		free(new->opt_val);
204	}
205	else
206		new = calloc (1, sizeof (XF86OptionRec));
207	new->opt_name = name;
208	new->opt_val = val;
209	new->opt_used = used;
210
211	if (old)
212		return head;
213	return ((XF86OptionPtr) xf86addListItem ((glp) head, (glp) new));
214}
215
216XF86OptionPtr
217xf86addNewOption (XF86OptionPtr head, char *name, char *val)
218{
219	return addNewOption2(head, name, val, 0);
220}
221
222void
223xf86freeFlags (XF86ConfFlagsPtr flags)
224{
225	if (flags == NULL)
226		return;
227	xf86optionListFree (flags->flg_option_lst);
228	TestFree(flags->flg_comment);
229	free (flags);
230}
231
232XF86OptionPtr
233xf86optionListDup (XF86OptionPtr opt)
234{
235	XF86OptionPtr newopt = NULL;
236	char *val;
237
238	while (opt)
239	{
240		val = opt->opt_val ? strdup(opt->opt_val) : NULL;
241		newopt = xf86addNewOption(newopt, strdup(opt->opt_name), val);
242		newopt->opt_used = opt->opt_used;
243		if (opt->opt_comment)
244			newopt->opt_comment = strdup(opt->opt_comment);
245		opt = opt->list.next;
246	}
247	return newopt;
248}
249
250void
251xf86optionListFree (XF86OptionPtr opt)
252{
253	XF86OptionPtr prev;
254
255	while (opt)
256	{
257		TestFree (opt->opt_name);
258		TestFree (opt->opt_val);
259		TestFree (opt->opt_comment);
260		prev = opt;
261		opt = opt->list.next;
262		free (prev);
263	}
264}
265
266char *
267xf86optionName(XF86OptionPtr opt)
268{
269	if (opt)
270		return opt->opt_name;
271	return 0;
272}
273
274char *
275xf86optionValue(XF86OptionPtr opt)
276{
277	if (opt)
278		return opt->opt_val;
279	return 0;
280}
281
282XF86OptionPtr
283xf86newOption(char *name, char *value)
284{
285	XF86OptionPtr opt;
286
287	opt = calloc(1, sizeof (XF86OptionRec));
288	if (!opt)
289		return NULL;
290
291	opt->opt_used = 0;
292	opt->list.next = 0;
293	opt->opt_name = name;
294	opt->opt_val = value;
295
296	return opt;
297}
298
299XF86OptionPtr
300xf86nextOption(XF86OptionPtr list)
301{
302	if (!list)
303		return NULL;
304	return list->list.next;
305}
306
307/*
308 * this function searches the given option list for the named option and
309 * returns a pointer to the option rec if found. If not found, it returns
310 * NULL
311 */
312
313XF86OptionPtr
314xf86findOption (XF86OptionPtr list, const char *name)
315{
316	while (list)
317	{
318		if (xf86nameCompare (list->opt_name, name) == 0)
319			return list;
320		list = list->list.next;
321	}
322	return NULL;
323}
324
325/*
326 * this function searches the given option list for the named option. If
327 * found and the option has a parameter, a pointer to the parameter is
328 * returned.  If the option does not have a parameter an empty string is
329 * returned.  If the option is not found, a NULL is returned.
330 */
331
332char *
333xf86findOptionValue (XF86OptionPtr list, const char *name)
334{
335	XF86OptionPtr p = xf86findOption (list, name);
336
337	if (p)
338	{
339		if (p->opt_val)
340			return p->opt_val;
341		else
342			return "";
343	}
344	return NULL;
345}
346
347XF86OptionPtr
348xf86optionListCreate( const char **options, int count, int used )
349{
350	XF86OptionPtr p = NULL;
351	char *t1, *t2;
352	int i;
353
354	if (count == -1)
355	{
356		for (count = 0; options[count]; count++)
357			;
358	}
359	if( (count % 2) != 0 )
360	{
361		fprintf( stderr, "xf86optionListCreate: count must be an even number.\n" );
362		return NULL;
363	}
364	for (i = 0; i < count; i += 2)
365	{
366		t1 = strdup(options[i]);
367		t2 = strdup(options[i + 1]);
368		p = addNewOption2 (p, t1, t2, used);
369	}
370
371	return p;
372}
373
374/* the 2 given lists are merged. If an option with the same name is present in
375 * both, the option from the user list - specified in the second argument -
376 * is used. The end result is a single valid list of options. Duplicates
377 * are freed, and the original lists are no longer guaranteed to be complete.
378 */
379XF86OptionPtr
380xf86optionListMerge (XF86OptionPtr head, XF86OptionPtr tail)
381{
382	XF86OptionPtr a, b, ap = NULL, bp = NULL;
383
384	a = tail;
385	b = head;
386	while (tail && b) {
387		if (xf86nameCompare (a->opt_name, b->opt_name) == 0) {
388			if (b == head)
389				head = a;
390			else
391				bp->list.next = a;
392			if (a == tail)
393				tail = a->list.next;
394			else
395				ap->list.next = a->list.next;
396			a->list.next = b->list.next;
397			b->list.next = NULL;
398			xf86optionListFree (b);
399			b = a->list.next;
400			bp = a;
401			a = tail;
402			ap = NULL;
403		} else {
404			ap = a;
405			if (!(a = a->list.next)) {
406				a = tail;
407				bp = b;
408				b = b->list.next;
409				ap = NULL;
410			}
411		}
412	}
413
414	if (head) {
415		for (a = head; a->list.next; a = a->list.next)
416			;
417		a->list.next = tail;
418	} else
419		head = tail;
420
421	return head;
422}
423
424char *
425xf86uLongToString(unsigned long i)
426{
427	char *s;
428
429	if (asprintf(&s, "%lu", i) == -1)
430		return NULL;
431	return s;
432}
433
434XF86OptionPtr
435xf86parseOption(XF86OptionPtr head)
436{
437	XF86OptionPtr option, cnew, old;
438	char *name, *comment = NULL;
439	int token;
440
441	if ((token = xf86getSubToken(&comment)) != STRING) {
442		xf86parseError(BAD_OPTION_MSG, NULL);
443		free(comment);
444		return head;
445	}
446
447	name = val.str;
448	if ((token = xf86getSubToken(&comment)) == STRING) {
449		option = xf86newOption(name, val.str);
450		option->opt_comment = comment;
451		if ((token = xf86getToken(NULL)) == COMMENT)
452			option->opt_comment = xf86addComment(option->opt_comment, val.str);
453		else
454			xf86unGetToken(token);
455	}
456	else {
457		option = xf86newOption(name, NULL);
458		option->opt_comment = comment;
459		if (token == COMMENT)
460			option->opt_comment = xf86addComment(option->opt_comment, val.str);
461		else
462			xf86unGetToken(token);
463	}
464
465	old = NULL;
466
467	/* Don't allow duplicates */
468	if (head != NULL && (old = xf86findOption(head, name)) != NULL) {
469		cnew = old;
470		free(option->opt_name);
471		TestFree(option->opt_val);
472		TestFree(option->opt_comment);
473		free(option);
474	}
475	else
476		cnew = option;
477
478	if (old == NULL)
479		return ((XF86OptionPtr)xf86addListItem((glp)head, (glp)cnew));
480
481	return head;
482}
483
484void
485xf86printOptionList(FILE *fp, XF86OptionPtr list, int tabs)
486{
487	int i;
488
489	if (!list)
490		return;
491	while (list) {
492		for (i = 0; i < tabs; i++)
493			fputc('\t', fp);
494		if (list->opt_val)
495			fprintf(fp, "Option	    \"%s\" \"%s\"", list->opt_name, list->opt_val);
496		else
497			fprintf(fp, "Option	    \"%s\"", list->opt_name);
498		if (list->opt_comment)
499			fprintf(fp, "%s", list->opt_comment);
500		else
501			fputc('\n', fp);
502		list = list->list.next;
503	}
504}
505