1d5ac70f0Sopenharmony_ci/**
2d5ac70f0Sopenharmony_ci * \file conf.c
3d5ac70f0Sopenharmony_ci * \ingroup Configuration
4d5ac70f0Sopenharmony_ci * \brief Configuration helper functions
5d5ac70f0Sopenharmony_ci * \author Abramo Bagnara <abramo@alsa-project.org>
6d5ac70f0Sopenharmony_ci * \author Jaroslav Kysela <perex@perex.cz>
7d5ac70f0Sopenharmony_ci * \date 2000-2001
8d5ac70f0Sopenharmony_ci *
9d5ac70f0Sopenharmony_ci * Tree based, full nesting configuration functions.
10d5ac70f0Sopenharmony_ci *
11d5ac70f0Sopenharmony_ci * See the \ref conf page for more details.
12d5ac70f0Sopenharmony_ci */
13d5ac70f0Sopenharmony_ci/*
14d5ac70f0Sopenharmony_ci *  Configuration helper functions
15d5ac70f0Sopenharmony_ci *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>,
16d5ac70f0Sopenharmony_ci *			  Jaroslav Kysela <perex@perex.cz>
17d5ac70f0Sopenharmony_ci *
18d5ac70f0Sopenharmony_ci *
19d5ac70f0Sopenharmony_ci *   This library is free software; you can redistribute it and/or modify
20d5ac70f0Sopenharmony_ci *   it under the terms of the GNU Lesser General Public License as
21d5ac70f0Sopenharmony_ci *   published by the Free Software Foundation; either version 2.1 of
22d5ac70f0Sopenharmony_ci *   the License, or (at your option) any later version.
23d5ac70f0Sopenharmony_ci *
24d5ac70f0Sopenharmony_ci *   This program is distributed in the hope that it will be useful,
25d5ac70f0Sopenharmony_ci *   but WITHOUT ANY WARRANTY; without even the implied warranty of
26d5ac70f0Sopenharmony_ci *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27d5ac70f0Sopenharmony_ci *   GNU Lesser General Public License for more details.
28d5ac70f0Sopenharmony_ci *
29d5ac70f0Sopenharmony_ci *   You should have received a copy of the GNU Lesser General Public
30d5ac70f0Sopenharmony_ci *   License along with this library; if not, write to the Free Software
31d5ac70f0Sopenharmony_ci *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
32d5ac70f0Sopenharmony_ci *
33d5ac70f0Sopenharmony_ci */
34d5ac70f0Sopenharmony_ci
35d5ac70f0Sopenharmony_ci/*! \page conf Configuration files
36d5ac70f0Sopenharmony_ci
37d5ac70f0Sopenharmony_ci<P>Configuration files use a simple format allowing modern
38d5ac70f0Sopenharmony_cidata description like nesting and array assignments.</P>
39d5ac70f0Sopenharmony_ci
40d5ac70f0Sopenharmony_ci\section conf_whitespace Whitespace
41d5ac70f0Sopenharmony_ci
42d5ac70f0Sopenharmony_ciWhitespace is the collective name given to spaces (blanks), horizontal and
43d5ac70f0Sopenharmony_civertical tabs, newline characters, and comments. Whitespace can
44d5ac70f0Sopenharmony_ciindicate where configuration tokens start and end, but beyond this function,
45d5ac70f0Sopenharmony_ciany surplus whitespace is discarded. For example, the two sequences
46d5ac70f0Sopenharmony_ci
47d5ac70f0Sopenharmony_ci\code
48d5ac70f0Sopenharmony_ci  a 1 b 2
49d5ac70f0Sopenharmony_ci\endcode
50d5ac70f0Sopenharmony_ci
51d5ac70f0Sopenharmony_ciand
52d5ac70f0Sopenharmony_ci
53d5ac70f0Sopenharmony_ci\code
54d5ac70f0Sopenharmony_ci  a 1
55d5ac70f0Sopenharmony_ci     b 2
56d5ac70f0Sopenharmony_ci\endcode
57d5ac70f0Sopenharmony_ci
58d5ac70f0Sopenharmony_ciare lexically equivalent and parse identically to give the four tokens:
59d5ac70f0Sopenharmony_ci
60d5ac70f0Sopenharmony_ci\code
61d5ac70f0Sopenharmony_cia
62d5ac70f0Sopenharmony_ci1
63d5ac70f0Sopenharmony_cib
64d5ac70f0Sopenharmony_ci2
65d5ac70f0Sopenharmony_ci\endcode
66d5ac70f0Sopenharmony_ci
67d5ac70f0Sopenharmony_ciThe ASCII characters representing whitespace can occur within literal
68d5ac70f0Sopenharmony_cistrings, in which case they are protected from the normal parsing process
69d5ac70f0Sopenharmony_ci(they remain as part of the string). For example:
70d5ac70f0Sopenharmony_ci
71d5ac70f0Sopenharmony_ci\code
72d5ac70f0Sopenharmony_ci  name "John Smith"
73d5ac70f0Sopenharmony_ci\endcode
74d5ac70f0Sopenharmony_ci
75d5ac70f0Sopenharmony_ciparses to two tokens, including the single literal-string token "John
76d5ac70f0Sopenharmony_ciSmith".
77d5ac70f0Sopenharmony_ci
78d5ac70f0Sopenharmony_ci\section conf_linesplicing Line continuation with \
79d5ac70f0Sopenharmony_ci
80d5ac70f0Sopenharmony_ciA special case occurs if a newline character in a string is preceded
81d5ac70f0Sopenharmony_ciby a backslash (\). The backslash and the new line are both discarded,
82d5ac70f0Sopenharmony_ciallowing two physical lines of text to be treated as one unit.
83d5ac70f0Sopenharmony_ci
84d5ac70f0Sopenharmony_ci\code
85d5ac70f0Sopenharmony_ci"John \
86d5ac70f0Sopenharmony_ciSmith"
87d5ac70f0Sopenharmony_ci\endcode
88d5ac70f0Sopenharmony_ci
89d5ac70f0Sopenharmony_ciis parsed as "John Smith".
90d5ac70f0Sopenharmony_ci
91d5ac70f0Sopenharmony_ci\section conf_comments Comments
92d5ac70f0Sopenharmony_ci
93d5ac70f0Sopenharmony_ciA single-line comment begins with the character #. The comment can start
94d5ac70f0Sopenharmony_ciat any position, and extends to the end of the line.
95d5ac70f0Sopenharmony_ci
96d5ac70f0Sopenharmony_ci\code
97d5ac70f0Sopenharmony_ci  a 1  # this is a comment
98d5ac70f0Sopenharmony_ci\endcode
99d5ac70f0Sopenharmony_ci
100d5ac70f0Sopenharmony_ci\section conf_include Including configuration files
101d5ac70f0Sopenharmony_ci
102d5ac70f0Sopenharmony_ciTo include another configuration file, write the file name in angle brackets.
103d5ac70f0Sopenharmony_ciThe prefix \c confdir: will reference the global configuration directory.
104d5ac70f0Sopenharmony_ci
105d5ac70f0Sopenharmony_ci\code
106d5ac70f0Sopenharmony_ci</etc/alsa1.conf>
107d5ac70f0Sopenharmony_ci<confdir:pcm/surround.conf>
108d5ac70f0Sopenharmony_ci\endcode
109d5ac70f0Sopenharmony_ci
110d5ac70f0Sopenharmony_ci\section conf_punctuators Punctuators
111d5ac70f0Sopenharmony_ci
112d5ac70f0Sopenharmony_ciThe configuration punctuators (also known as separators) are:
113d5ac70f0Sopenharmony_ci
114d5ac70f0Sopenharmony_ci\code
115d5ac70f0Sopenharmony_ci  {} [] , ; = . ' " new-line form-feed carriage-return whitespace
116d5ac70f0Sopenharmony_ci\endcode
117d5ac70f0Sopenharmony_ci
118d5ac70f0Sopenharmony_ci\subsection conf_braces Braces
119d5ac70f0Sopenharmony_ci
120d5ac70f0Sopenharmony_ciOpening and closing braces { } indicate the start and end of a compound
121d5ac70f0Sopenharmony_cistatement:
122d5ac70f0Sopenharmony_ci
123d5ac70f0Sopenharmony_ci\code
124d5ac70f0Sopenharmony_cia {
125d5ac70f0Sopenharmony_ci  b 1
126d5ac70f0Sopenharmony_ci}
127d5ac70f0Sopenharmony_ci\endcode
128d5ac70f0Sopenharmony_ci
129d5ac70f0Sopenharmony_ci\subsection conf_brackets Brackets
130d5ac70f0Sopenharmony_ci
131d5ac70f0Sopenharmony_ciOpening and closing brackets indicate a single array definition. The
132d5ac70f0Sopenharmony_ciidentifiers are automatically generated starting with zero.
133d5ac70f0Sopenharmony_ci
134d5ac70f0Sopenharmony_ci\code
135d5ac70f0Sopenharmony_cia [
136d5ac70f0Sopenharmony_ci  "first"
137d5ac70f0Sopenharmony_ci  "second"
138d5ac70f0Sopenharmony_ci]
139d5ac70f0Sopenharmony_ci\endcode
140d5ac70f0Sopenharmony_ci
141d5ac70f0Sopenharmony_ciThe above code is equal to
142d5ac70f0Sopenharmony_ci
143d5ac70f0Sopenharmony_ci\code
144d5ac70f0Sopenharmony_cia.0 "first"
145d5ac70f0Sopenharmony_cia.1 "second"
146d5ac70f0Sopenharmony_ci\endcode
147d5ac70f0Sopenharmony_ci
148d5ac70f0Sopenharmony_ci\subsection conf_comma_semicolon Comma and semicolon
149d5ac70f0Sopenharmony_ci
150d5ac70f0Sopenharmony_ciThe comma (,) or semicolon (;) can separate value assignments. It is not
151d5ac70f0Sopenharmony_cistrictly required to use these separators because whitespace suffices to
152d5ac70f0Sopenharmony_ciseparate tokens.
153d5ac70f0Sopenharmony_ci
154d5ac70f0Sopenharmony_ci\code
155d5ac70f0Sopenharmony_cia 1;
156d5ac70f0Sopenharmony_cib 1,
157d5ac70f0Sopenharmony_ci\endcode
158d5ac70f0Sopenharmony_ci
159d5ac70f0Sopenharmony_ci\subsection conf_equal Equal sign
160d5ac70f0Sopenharmony_ci
161d5ac70f0Sopenharmony_ciThe equal sign (=) can separate variable declarations from
162d5ac70f0Sopenharmony_ciinitialization lists:
163d5ac70f0Sopenharmony_ci
164d5ac70f0Sopenharmony_ci\code
165d5ac70f0Sopenharmony_cia=1
166d5ac70f0Sopenharmony_cib=2
167d5ac70f0Sopenharmony_ci\endcode
168d5ac70f0Sopenharmony_ci
169d5ac70f0Sopenharmony_ciUsing equal signs is not required because whitespace suffices to separate
170d5ac70f0Sopenharmony_citokens.
171d5ac70f0Sopenharmony_ci
172d5ac70f0Sopenharmony_ci\section conf_assigns Assignments
173d5ac70f0Sopenharmony_ci
174d5ac70f0Sopenharmony_ciThe configuration file defines id (key) and value pairs. The id (key) can be
175d5ac70f0Sopenharmony_cicomposed from ASCII digits, characters from a to z and A to Z, and the
176d5ac70f0Sopenharmony_ciunderscore (_). The value can be either a string, an integer, a real number,
177d5ac70f0Sopenharmony_cior a compound statement.
178d5ac70f0Sopenharmony_ci
179d5ac70f0Sopenharmony_ci\subsection conf_single Single assignments
180d5ac70f0Sopenharmony_ci
181d5ac70f0Sopenharmony_ci\code
182d5ac70f0Sopenharmony_cia 1	# is equal to
183d5ac70f0Sopenharmony_cia=1	# is equal to
184d5ac70f0Sopenharmony_cia=1;	# is equal to
185d5ac70f0Sopenharmony_cia 1,
186d5ac70f0Sopenharmony_ci\endcode
187d5ac70f0Sopenharmony_ci
188d5ac70f0Sopenharmony_ci\subsection conf_compound Compound assignments (definitions using braces)
189d5ac70f0Sopenharmony_ci
190d5ac70f0Sopenharmony_ci\code
191d5ac70f0Sopenharmony_cia {
192d5ac70f0Sopenharmony_ci  b = 1
193d5ac70f0Sopenharmony_ci}
194d5ac70f0Sopenharmony_cia={
195d5ac70f0Sopenharmony_ci  b 1,
196d5ac70f0Sopenharmony_ci}
197d5ac70f0Sopenharmony_ci\endcode
198d5ac70f0Sopenharmony_ci
199d5ac70f0Sopenharmony_ci\section conf_compound1 Compound assignments (one key definitions)
200d5ac70f0Sopenharmony_ci
201d5ac70f0Sopenharmony_ci\code
202d5ac70f0Sopenharmony_cia.b 1
203d5ac70f0Sopenharmony_cia.b=1
204d5ac70f0Sopenharmony_ci\endcode
205d5ac70f0Sopenharmony_ci
206d5ac70f0Sopenharmony_ci\subsection conf_array Array assignments (definitions using brackets)
207d5ac70f0Sopenharmony_ci
208d5ac70f0Sopenharmony_ci\code
209d5ac70f0Sopenharmony_cia [
210d5ac70f0Sopenharmony_ci  "first"
211d5ac70f0Sopenharmony_ci  "second"
212d5ac70f0Sopenharmony_ci]
213d5ac70f0Sopenharmony_ci\endcode
214d5ac70f0Sopenharmony_ci
215d5ac70f0Sopenharmony_ci\subsection conf_array1 Array assignments (one key definitions)
216d5ac70f0Sopenharmony_ci
217d5ac70f0Sopenharmony_ci\code
218d5ac70f0Sopenharmony_cia.0 "first"
219d5ac70f0Sopenharmony_cia.1 "second"
220d5ac70f0Sopenharmony_ci\endcode
221d5ac70f0Sopenharmony_ci
222d5ac70f0Sopenharmony_ci\section conf_mode Operation modes for parsing nodes
223d5ac70f0Sopenharmony_ci
224d5ac70f0Sopenharmony_ciBy default, the node operation mode is 'merge+create', i.e., if
225d5ac70f0Sopenharmony_cia configuration node is not present a new one is created, otherwise
226d5ac70f0Sopenharmony_cithe latest assignment is merged (if possible - type checking). The
227d5ac70f0Sopenharmony_ci'merge+create' operation mode is specified with the prefix character plus (+).
228d5ac70f0Sopenharmony_ci
229d5ac70f0Sopenharmony_ciThe operation mode 'merge' merges the node with the old one (which must
230d5ac70f0Sopenharmony_ciexist). Type checking is done, so strings cannot be assigned to integers
231d5ac70f0Sopenharmony_ciand so on. This mode is specified with the prefix character minus (-).
232d5ac70f0Sopenharmony_ci
233d5ac70f0Sopenharmony_ciThe operation mode 'do not override' ignores a new configuration node
234d5ac70f0Sopenharmony_ciif a configuration node with the same name exists. This mode is specified with
235d5ac70f0Sopenharmony_cithe prefix character question mark (?).
236d5ac70f0Sopenharmony_ci
237d5ac70f0Sopenharmony_ciThe operation mode 'override' always overrides the old configuration node
238d5ac70f0Sopenharmony_ciwith new contents. This mode is specified with the prefix character
239d5ac70f0Sopenharmony_ciexclamation mark (!).
240d5ac70f0Sopenharmony_ci
241d5ac70f0Sopenharmony_ci\code
242d5ac70f0Sopenharmony_cidefaults.pcm.!device 1
243d5ac70f0Sopenharmony_ci\endcode
244d5ac70f0Sopenharmony_ci
245d5ac70f0Sopenharmony_ci\section conf_syntax_summary Syntax summary
246d5ac70f0Sopenharmony_ci
247d5ac70f0Sopenharmony_ci\code
248d5ac70f0Sopenharmony_ci# Configuration file syntax
249d5ac70f0Sopenharmony_ci
250d5ac70f0Sopenharmony_ci# Include a new configuration file
251d5ac70f0Sopenharmony_ci<filename>
252d5ac70f0Sopenharmony_ci
253d5ac70f0Sopenharmony_ci# Simple assignment
254d5ac70f0Sopenharmony_ciname [=] value [,|;]
255d5ac70f0Sopenharmony_ci
256d5ac70f0Sopenharmony_ci# Compound assignment (first style)
257d5ac70f0Sopenharmony_ciname [=] {
258d5ac70f0Sopenharmony_ci        name1 [=] value [,|;]
259d5ac70f0Sopenharmony_ci        ...
260d5ac70f0Sopenharmony_ci}
261d5ac70f0Sopenharmony_ci
262d5ac70f0Sopenharmony_ci# Compound assignment (second style)
263d5ac70f0Sopenharmony_ciname.name1 [=] value [,|;]
264d5ac70f0Sopenharmony_ci
265d5ac70f0Sopenharmony_ci# Array assignment (first style)
266d5ac70f0Sopenharmony_ciname [
267d5ac70f0Sopenharmony_ci        value0 [,|;]
268d5ac70f0Sopenharmony_ci        value1 [,|;]
269d5ac70f0Sopenharmony_ci        ...
270d5ac70f0Sopenharmony_ci]
271d5ac70f0Sopenharmony_ci
272d5ac70f0Sopenharmony_ci# Array assignment (second style)
273d5ac70f0Sopenharmony_ciname.0 [=] value0 [,|;]
274d5ac70f0Sopenharmony_ciname.1 [=] value1 [,|;]
275d5ac70f0Sopenharmony_ci\endcode
276d5ac70f0Sopenharmony_ci
277d5ac70f0Sopenharmony_ci\section conf_syntax_ref References
278d5ac70f0Sopenharmony_ci
279d5ac70f0Sopenharmony_ci\ref confarg
280d5ac70f0Sopenharmony_ci\ref conffunc
281d5ac70f0Sopenharmony_ci\ref confhooks
282d5ac70f0Sopenharmony_ci
283d5ac70f0Sopenharmony_ci*/
284d5ac70f0Sopenharmony_ci
285d5ac70f0Sopenharmony_ci/*! \page confarg Runtime arguments in configuration files
286d5ac70f0Sopenharmony_ci
287d5ac70f0Sopenharmony_ci<P>The ALSA library can accept runtime arguments for some configuration
288d5ac70f0Sopenharmony_ciblocks. This extension is built on top of the basic configuration file
289d5ac70f0Sopenharmony_cisyntax.<P>
290d5ac70f0Sopenharmony_ci
291d5ac70f0Sopenharmony_ci\section confarg_define Defining arguments
292d5ac70f0Sopenharmony_ci
293d5ac70f0Sopenharmony_ciArguments are defined using the id (key) \c \@args and array values containing
294d5ac70f0Sopenharmony_cithe string names of the arguments:
295d5ac70f0Sopenharmony_ci
296d5ac70f0Sopenharmony_ci\code
297d5ac70f0Sopenharmony_ci@args [ CARD ]	# or
298d5ac70f0Sopenharmony_ci@args.0 CARD
299d5ac70f0Sopenharmony_ci\endcode
300d5ac70f0Sopenharmony_ci
301d5ac70f0Sopenharmony_ci\section confarg_type Defining argument types and default values
302d5ac70f0Sopenharmony_ci
303d5ac70f0Sopenharmony_ciAn argument's type is specified with the id (key) \c \@args and the argument
304d5ac70f0Sopenharmony_ciname. The type and the default value are specified in the compound block:
305d5ac70f0Sopenharmony_ci
306d5ac70f0Sopenharmony_ci\code
307d5ac70f0Sopenharmony_ci@args.CARD {
308d5ac70f0Sopenharmony_ci  type string
309d5ac70f0Sopenharmony_ci  default "abcd"
310d5ac70f0Sopenharmony_ci}
311d5ac70f0Sopenharmony_ci\endcode
312d5ac70f0Sopenharmony_ci
313d5ac70f0Sopenharmony_ci\section confarg_refer Referring to arguments
314d5ac70f0Sopenharmony_ci
315d5ac70f0Sopenharmony_ciArguments are referred to with a dollar-sign ($) and the name of the argument:
316d5ac70f0Sopenharmony_ci
317d5ac70f0Sopenharmony_ci\code
318d5ac70f0Sopenharmony_ci  card $CARD
319d5ac70f0Sopenharmony_ci\endcode
320d5ac70f0Sopenharmony_ci
321d5ac70f0Sopenharmony_ci\section confarg_math simple math expressions
322d5ac70f0Sopenharmony_ci
323d5ac70f0Sopenharmony_ciThe simple math expressions are identified using a unix shell like expression syntax
324d5ac70f0Sopenharmony_ciwith a dollar-sign ($) and bracket ([):
325d5ac70f0Sopenharmony_ci
326d5ac70f0Sopenharmony_ci\code
327d5ac70f0Sopenharmony_ci  card "$[$CARD + 1]"
328d5ac70f0Sopenharmony_ci\endcode
329d5ac70f0Sopenharmony_ci
330d5ac70f0Sopenharmony_ci\section confarg_usage Usage
331d5ac70f0Sopenharmony_ci
332d5ac70f0Sopenharmony_ciTo use a block with arguments, write the argument values after the key,
333d5ac70f0Sopenharmony_ciseparated with a colon (:). For example, all these names for PCM interfaces
334d5ac70f0Sopenharmony_cigive the same result:
335d5ac70f0Sopenharmony_ci
336d5ac70f0Sopenharmony_ci\code
337d5ac70f0Sopenharmony_cihw:0,1
338d5ac70f0Sopenharmony_cihw:CARD=0,DEV=1
339d5ac70f0Sopenharmony_cihw:{CARD 0 DEV 1}
340d5ac70f0Sopenharmony_ciplug:"hw:0,1"
341d5ac70f0Sopenharmony_ciplug:{SLAVE="hw:{CARD 0 DEV 1}"}
342d5ac70f0Sopenharmony_ci\endcode
343d5ac70f0Sopenharmony_ci
344d5ac70f0Sopenharmony_ciAs you see, arguments can be specified in their proper order or by name.
345d5ac70f0Sopenharmony_ciNote that arguments enclosed in braces are parsed in the same way as in
346d5ac70f0Sopenharmony_ciconfiguration files, but using the override method by default.
347d5ac70f0Sopenharmony_ci
348d5ac70f0Sopenharmony_ci\section confarg_example Example
349d5ac70f0Sopenharmony_ci
350d5ac70f0Sopenharmony_ci\code
351d5ac70f0Sopenharmony_cipcm.demo {
352d5ac70f0Sopenharmony_ci	@args [ CARD DEVICE ]
353d5ac70f0Sopenharmony_ci	@args.CARD {
354d5ac70f0Sopenharmony_ci		type string
355d5ac70f0Sopenharmony_ci		default "supersonic"
356d5ac70f0Sopenharmony_ci	}
357d5ac70f0Sopenharmony_ci	@args.DEVICE {
358d5ac70f0Sopenharmony_ci		type integer
359d5ac70f0Sopenharmony_ci		default 0
360d5ac70f0Sopenharmony_ci	}
361d5ac70f0Sopenharmony_ci	type hw
362d5ac70f0Sopenharmony_ci	card $CARD
363d5ac70f0Sopenharmony_ci	device $DEVICE
364d5ac70f0Sopenharmony_ci}
365d5ac70f0Sopenharmony_ci\endcode
366d5ac70f0Sopenharmony_ci
367d5ac70f0Sopenharmony_ci
368d5ac70f0Sopenharmony_ci*/
369d5ac70f0Sopenharmony_ci
370d5ac70f0Sopenharmony_ci/*! \page conffunc Runtime functions in configuration files
371d5ac70f0Sopenharmony_ci
372d5ac70f0Sopenharmony_ci<P>The ALSA library can modify the configuration at runtime.
373d5ac70f0Sopenharmony_ciSeveral built-in functions are available.</P>
374d5ac70f0Sopenharmony_ci
375d5ac70f0Sopenharmony_ci<P>A function is defined with the id \c \@func and the function name. All other
376d5ac70f0Sopenharmony_civalues in the current compound are used as configuration for the function.
377d5ac70f0Sopenharmony_ciIf the compound func.\<function_name\> is defined in the root node, then the
378d5ac70f0Sopenharmony_cilibrary and function from this compound configuration are used, otherwise
379d5ac70f0Sopenharmony_ci'snd_func_' is prefixed to the string and code from the ALSA library is used.
380d5ac70f0Sopenharmony_ciThe definition of a function looks like:</P>
381d5ac70f0Sopenharmony_ci
382d5ac70f0Sopenharmony_ci\code
383d5ac70f0Sopenharmony_cifunc.remove_first_char {
384d5ac70f0Sopenharmony_ci	lib "/usr/lib/libasoundextend.so"
385d5ac70f0Sopenharmony_ci	func "extend_remove_first_char"
386d5ac70f0Sopenharmony_ci}
387d5ac70f0Sopenharmony_ci\endcode
388d5ac70f0Sopenharmony_ci
389d5ac70f0Sopenharmony_ci*/
390d5ac70f0Sopenharmony_ci
391d5ac70f0Sopenharmony_ci/*! \page confhooks Hooks in configuration files
392d5ac70f0Sopenharmony_ci
393d5ac70f0Sopenharmony_ci<P>The hook extension in the ALSA library allows expansion of configuration
394d5ac70f0Sopenharmony_cinodes at run-time. The existence of a hook is determined by the
395d5ac70f0Sopenharmony_cipresence of a \@hooks compound node.</P>
396d5ac70f0Sopenharmony_ci
397d5ac70f0Sopenharmony_ci<P>This example defines a hook which loads two configuration files at the
398d5ac70f0Sopenharmony_cibeginning:</P>
399d5ac70f0Sopenharmony_ci
400d5ac70f0Sopenharmony_ci\code
401d5ac70f0Sopenharmony_ci@hooks [
402d5ac70f0Sopenharmony_ci	{
403d5ac70f0Sopenharmony_ci		func load
404d5ac70f0Sopenharmony_ci		files [
405d5ac70f0Sopenharmony_ci			"/etc/asound.conf"
406d5ac70f0Sopenharmony_ci			"~/.asoundrc"
407d5ac70f0Sopenharmony_ci		]
408d5ac70f0Sopenharmony_ci		errors false
409d5ac70f0Sopenharmony_ci	}
410d5ac70f0Sopenharmony_ci]
411d5ac70f0Sopenharmony_ci\endcode
412d5ac70f0Sopenharmony_ci
413d5ac70f0Sopenharmony_ci\section confhooks_ref Function reference
414d5ac70f0Sopenharmony_ci
415d5ac70f0Sopenharmony_ci<UL>
416d5ac70f0Sopenharmony_ci  <LI>The function load - \c snd_config_hook_load() - loads and parses the
417d5ac70f0Sopenharmony_ci      given configuration files.
418d5ac70f0Sopenharmony_ci  <LI>The function load_for_all_cards - \c snd_config_hook_load_for_all_cards() -
419d5ac70f0Sopenharmony_ci      loads and parses the given configuration files for each installed sound
420d5ac70f0Sopenharmony_ci      card. The driver name (the type of the sound card) is passed in the
421d5ac70f0Sopenharmony_ci      private configuration node.
422d5ac70f0Sopenharmony_ci</UL>
423d5ac70f0Sopenharmony_ci
424d5ac70f0Sopenharmony_ci*/
425d5ac70f0Sopenharmony_ci
426d5ac70f0Sopenharmony_ci
427d5ac70f0Sopenharmony_ci#include "local.h"
428d5ac70f0Sopenharmony_ci#include <stdarg.h>
429d5ac70f0Sopenharmony_ci#include <stdbool.h>
430d5ac70f0Sopenharmony_ci#include <limits.h>
431d5ac70f0Sopenharmony_ci#include <sys/stat.h>
432d5ac70f0Sopenharmony_ci#include <dirent.h>
433d5ac70f0Sopenharmony_ci#include <locale.h>
434d5ac70f0Sopenharmony_ci#ifdef HAVE_LIBPTHREAD
435d5ac70f0Sopenharmony_ci#include <pthread.h>
436d5ac70f0Sopenharmony_ci#endif
437d5ac70f0Sopenharmony_ci
438d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN
439d5ac70f0Sopenharmony_ci
440d5ac70f0Sopenharmony_ci#ifdef HAVE_LIBPTHREAD
441d5ac70f0Sopenharmony_cistatic pthread_mutex_t snd_config_update_mutex;
442d5ac70f0Sopenharmony_cistatic pthread_once_t snd_config_update_mutex_once = PTHREAD_ONCE_INIT;
443d5ac70f0Sopenharmony_ci#endif
444d5ac70f0Sopenharmony_ci
445d5ac70f0Sopenharmony_cistruct _snd_config {
446d5ac70f0Sopenharmony_ci	char *id;
447d5ac70f0Sopenharmony_ci	snd_config_type_t type;
448d5ac70f0Sopenharmony_ci	int refcount; /* default = 0 */
449d5ac70f0Sopenharmony_ci	union {
450d5ac70f0Sopenharmony_ci		long integer;
451d5ac70f0Sopenharmony_ci		long long integer64;
452d5ac70f0Sopenharmony_ci		char *string;
453d5ac70f0Sopenharmony_ci		double real;
454d5ac70f0Sopenharmony_ci		const void *ptr;
455d5ac70f0Sopenharmony_ci		struct {
456d5ac70f0Sopenharmony_ci			struct list_head fields;
457d5ac70f0Sopenharmony_ci			bool join;
458d5ac70f0Sopenharmony_ci		} compound;
459d5ac70f0Sopenharmony_ci	} u;
460d5ac70f0Sopenharmony_ci	struct list_head list;
461d5ac70f0Sopenharmony_ci	snd_config_t *parent;
462d5ac70f0Sopenharmony_ci	int hop;
463d5ac70f0Sopenharmony_ci};
464d5ac70f0Sopenharmony_ci
465d5ac70f0Sopenharmony_cistruct filedesc {
466d5ac70f0Sopenharmony_ci	char *name;
467d5ac70f0Sopenharmony_ci	snd_input_t *in;
468d5ac70f0Sopenharmony_ci	unsigned int line, column;
469d5ac70f0Sopenharmony_ci	struct filedesc *next;
470d5ac70f0Sopenharmony_ci
471d5ac70f0Sopenharmony_ci	/* list of the include paths (configuration directories),
472d5ac70f0Sopenharmony_ci	 * defined by <searchdir:relative-path/to/top-alsa-conf-dir>,
473d5ac70f0Sopenharmony_ci	 * for searching its included files.
474d5ac70f0Sopenharmony_ci	 */
475d5ac70f0Sopenharmony_ci	struct list_head include_paths;
476d5ac70f0Sopenharmony_ci};
477d5ac70f0Sopenharmony_ci
478d5ac70f0Sopenharmony_ci/* path to search included files */
479d5ac70f0Sopenharmony_cistruct include_path {
480d5ac70f0Sopenharmony_ci	char *dir;
481d5ac70f0Sopenharmony_ci	struct list_head list;
482d5ac70f0Sopenharmony_ci};
483d5ac70f0Sopenharmony_ci
484d5ac70f0Sopenharmony_ci#define LOCAL_ERROR			(-0x68000000)
485d5ac70f0Sopenharmony_ci
486d5ac70f0Sopenharmony_ci#define LOCAL_UNTERMINATED_STRING 	(LOCAL_ERROR - 0)
487d5ac70f0Sopenharmony_ci#define LOCAL_UNTERMINATED_QUOTE	(LOCAL_ERROR - 1)
488d5ac70f0Sopenharmony_ci#define LOCAL_UNEXPECTED_CHAR		(LOCAL_ERROR - 2)
489d5ac70f0Sopenharmony_ci#define LOCAL_UNEXPECTED_EOF		(LOCAL_ERROR - 3)
490d5ac70f0Sopenharmony_ci
491d5ac70f0Sopenharmony_citypedef struct {
492d5ac70f0Sopenharmony_ci	struct filedesc *current;
493d5ac70f0Sopenharmony_ci	int unget;
494d5ac70f0Sopenharmony_ci	int ch;
495d5ac70f0Sopenharmony_ci} input_t;
496d5ac70f0Sopenharmony_ci
497d5ac70f0Sopenharmony_ci#ifdef HAVE_LIBPTHREAD
498d5ac70f0Sopenharmony_ci
499d5ac70f0Sopenharmony_cistatic void snd_config_init_mutex(void)
500d5ac70f0Sopenharmony_ci{
501d5ac70f0Sopenharmony_ci	pthread_mutexattr_t attr;
502d5ac70f0Sopenharmony_ci
503d5ac70f0Sopenharmony_ci	pthread_mutexattr_init(&attr);
504d5ac70f0Sopenharmony_ci#ifdef HAVE_PTHREAD_MUTEX_RECURSIVE
505d5ac70f0Sopenharmony_ci	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
506d5ac70f0Sopenharmony_ci#endif
507d5ac70f0Sopenharmony_ci	pthread_mutex_init(&snd_config_update_mutex, &attr);
508d5ac70f0Sopenharmony_ci	pthread_mutexattr_destroy(&attr);
509d5ac70f0Sopenharmony_ci}
510d5ac70f0Sopenharmony_ci
511d5ac70f0Sopenharmony_cistatic inline void snd_config_lock(void)
512d5ac70f0Sopenharmony_ci{
513d5ac70f0Sopenharmony_ci	pthread_once(&snd_config_update_mutex_once, snd_config_init_mutex);
514d5ac70f0Sopenharmony_ci	pthread_mutex_lock(&snd_config_update_mutex);
515d5ac70f0Sopenharmony_ci}
516d5ac70f0Sopenharmony_ci
517d5ac70f0Sopenharmony_cistatic inline void snd_config_unlock(void)
518d5ac70f0Sopenharmony_ci{
519d5ac70f0Sopenharmony_ci	pthread_mutex_unlock(&snd_config_update_mutex);
520d5ac70f0Sopenharmony_ci}
521d5ac70f0Sopenharmony_ci
522d5ac70f0Sopenharmony_ci#else
523d5ac70f0Sopenharmony_ci
524d5ac70f0Sopenharmony_cistatic inline void snd_config_lock(void) { }
525d5ac70f0Sopenharmony_cistatic inline void snd_config_unlock(void) { }
526d5ac70f0Sopenharmony_ci
527d5ac70f0Sopenharmony_ci#endif
528d5ac70f0Sopenharmony_ci
529d5ac70f0Sopenharmony_ci/*
530d5ac70f0Sopenharmony_ci * Add a directory to the paths to search included files.
531d5ac70f0Sopenharmony_ci * param fd -  File object that owns these paths to search files included by it.
532d5ac70f0Sopenharmony_ci * param dir - Path of the directory to add. Allocated externally and need to
533d5ac70f0Sopenharmony_ci*              be freed manually later.
534d5ac70f0Sopenharmony_ci * return - Zero if successful, otherwise a negative error code.
535d5ac70f0Sopenharmony_ci *
536d5ac70f0Sopenharmony_ci * The direcotry should be a subdiretory of top configuration directory
537d5ac70f0Sopenharmony_ci * "/usr/share/alsa/".
538d5ac70f0Sopenharmony_ci */
539d5ac70f0Sopenharmony_cistatic int add_include_path(struct filedesc *fd, const char *dir)
540d5ac70f0Sopenharmony_ci{
541d5ac70f0Sopenharmony_ci	struct include_path *path;
542d5ac70f0Sopenharmony_ci	struct filedesc *fd1;
543d5ac70f0Sopenharmony_ci	struct list_head *pos;
544d5ac70f0Sopenharmony_ci
545d5ac70f0Sopenharmony_ci	/* check, if dir is already registered (also in parents) */
546d5ac70f0Sopenharmony_ci	for (fd1 = fd; fd1; fd1 = fd1->next) {
547d5ac70f0Sopenharmony_ci		list_for_each(pos, &fd1->include_paths) {
548d5ac70f0Sopenharmony_ci			path = list_entry(pos, struct include_path, list);
549d5ac70f0Sopenharmony_ci			if (strcmp(path->dir, dir) == 0)
550d5ac70f0Sopenharmony_ci				return 0;
551d5ac70f0Sopenharmony_ci		}
552d5ac70f0Sopenharmony_ci	}
553d5ac70f0Sopenharmony_ci
554d5ac70f0Sopenharmony_ci	path = calloc(1, sizeof(*path));
555d5ac70f0Sopenharmony_ci	if (!path)
556d5ac70f0Sopenharmony_ci		return -ENOMEM;
557d5ac70f0Sopenharmony_ci
558d5ac70f0Sopenharmony_ci	path->dir = strdup(dir);
559d5ac70f0Sopenharmony_ci	if (path->dir == NULL) {
560d5ac70f0Sopenharmony_ci		free(path);
561d5ac70f0Sopenharmony_ci		return -ENOMEM;
562d5ac70f0Sopenharmony_ci	}
563d5ac70f0Sopenharmony_ci
564d5ac70f0Sopenharmony_ci	list_add_tail(&path->list, &fd->include_paths);
565d5ac70f0Sopenharmony_ci	return 0;
566d5ac70f0Sopenharmony_ci}
567d5ac70f0Sopenharmony_ci
568d5ac70f0Sopenharmony_ci/*
569d5ac70f0Sopenharmony_ci * Free all include paths of a file descriptor.
570d5ac70f0Sopenharmony_ci * param fd - File object that owns these paths to search files included by it.
571d5ac70f0Sopenharmony_ci */
572d5ac70f0Sopenharmony_cistatic void free_include_paths(struct filedesc *fd)
573d5ac70f0Sopenharmony_ci{
574d5ac70f0Sopenharmony_ci	struct list_head *pos, *npos, *base;
575d5ac70f0Sopenharmony_ci	struct include_path *path;
576d5ac70f0Sopenharmony_ci
577d5ac70f0Sopenharmony_ci	base = &fd->include_paths;
578d5ac70f0Sopenharmony_ci	list_for_each_safe(pos, npos, base) {
579d5ac70f0Sopenharmony_ci		path = list_entry(pos, struct include_path, list);
580d5ac70f0Sopenharmony_ci		list_del(&path->list);
581d5ac70f0Sopenharmony_ci		if (path->dir)
582d5ac70f0Sopenharmony_ci			free(path->dir);
583d5ac70f0Sopenharmony_ci		free(path);
584d5ac70f0Sopenharmony_ci	}
585d5ac70f0Sopenharmony_ci}
586d5ac70f0Sopenharmony_ci
587d5ac70f0Sopenharmony_ci#endif /* DOC_HIDDEN */
588d5ac70f0Sopenharmony_ci
589d5ac70f0Sopenharmony_ci/**
590d5ac70f0Sopenharmony_ci * \brief Returns the default top-level config directory
591d5ac70f0Sopenharmony_ci * \return The top-level config directory path string
592d5ac70f0Sopenharmony_ci *
593d5ac70f0Sopenharmony_ci * This function returns the string of the top-level config directory path.
594d5ac70f0Sopenharmony_ci * If the path is specified via the environment variable \c ALSA_CONFIG_DIR
595d5ac70f0Sopenharmony_ci * and the value is a valid path, it returns this value.  If unspecified, it
596d5ac70f0Sopenharmony_ci * returns the default value, "/usr/share/alsa".
597d5ac70f0Sopenharmony_ci */
598d5ac70f0Sopenharmony_ciconst char *snd_config_topdir(void)
599d5ac70f0Sopenharmony_ci{
600d5ac70f0Sopenharmony_ci	static char *topdir;
601d5ac70f0Sopenharmony_ci
602d5ac70f0Sopenharmony_ci	if (!topdir) {
603d5ac70f0Sopenharmony_ci		topdir = getenv("ALSA_CONFIG_DIR");
604d5ac70f0Sopenharmony_ci		if (!topdir || *topdir != '/' || strlen(topdir) >= PATH_MAX)
605d5ac70f0Sopenharmony_ci			topdir = ALSA_CONFIG_DIR;
606d5ac70f0Sopenharmony_ci	}
607d5ac70f0Sopenharmony_ci	return topdir;
608d5ac70f0Sopenharmony_ci}
609d5ac70f0Sopenharmony_ci
610d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN
611d5ac70f0Sopenharmony_ci
612d5ac70f0Sopenharmony_cistatic char *_snd_config_path(const char *name)
613d5ac70f0Sopenharmony_ci{
614d5ac70f0Sopenharmony_ci	const char *root = snd_config_topdir();
615d5ac70f0Sopenharmony_ci	char *path = malloc(strlen(root) + strlen(name) + 2);
616d5ac70f0Sopenharmony_ci	if (!path)
617d5ac70f0Sopenharmony_ci		return NULL;
618d5ac70f0Sopenharmony_ci	sprintf(path, "%s/%s", root, name);
619d5ac70f0Sopenharmony_ci	return path;
620d5ac70f0Sopenharmony_ci}
621d5ac70f0Sopenharmony_ci
622d5ac70f0Sopenharmony_ci/*
623d5ac70f0Sopenharmony_ci * Search and open a file, and creates a new input object reading from the file.
624d5ac70f0Sopenharmony_ci * param inputp - The functions puts the pointer to the new input object
625d5ac70f0Sopenharmony_ci *               at the address specified by \p inputp.
626d5ac70f0Sopenharmony_ci * param file - Name of the configuration file.
627d5ac70f0Sopenharmony_ci * param include_paths - Optional, addtional directories to search the file.
628d5ac70f0Sopenharmony_ci * return - Zero if successful, otherwise a negative error code.
629d5ac70f0Sopenharmony_ci *
630d5ac70f0Sopenharmony_ci * This function will search and open the file in the following order
631d5ac70f0Sopenharmony_ci * of priority:
632d5ac70f0Sopenharmony_ci * 1. directly open the file by its name (only if absolute)
633d5ac70f0Sopenharmony_ci * 2. search for the file name in in additional configuration directories
634d5ac70f0Sopenharmony_ci *    specified by users, via alsaconf syntax
635d5ac70f0Sopenharmony_ci *    <searchdir:relative-path/to/user/share/alsa>;
636d5ac70f0Sopenharmony_ci *    These directories should be subdirectories of /usr/share/alsa.
637d5ac70f0Sopenharmony_ci */
638d5ac70f0Sopenharmony_cistatic int input_stdio_open(snd_input_t **inputp, const char *file,
639d5ac70f0Sopenharmony_ci			    struct filedesc *current)
640d5ac70f0Sopenharmony_ci{
641d5ac70f0Sopenharmony_ci	struct list_head *pos;
642d5ac70f0Sopenharmony_ci	struct include_path *path;
643d5ac70f0Sopenharmony_ci	char full_path[PATH_MAX];
644d5ac70f0Sopenharmony_ci	int err;
645d5ac70f0Sopenharmony_ci
646d5ac70f0Sopenharmony_ci	if (file[0] == '/')
647d5ac70f0Sopenharmony_ci		return snd_input_stdio_open(inputp, file, "r");
648d5ac70f0Sopenharmony_ci
649d5ac70f0Sopenharmony_ci	/* search file in user specified include paths. These directories
650d5ac70f0Sopenharmony_ci	 * are subdirectories of /usr/share/alsa.
651d5ac70f0Sopenharmony_ci	 */
652d5ac70f0Sopenharmony_ci	err = -ENOENT;
653d5ac70f0Sopenharmony_ci	while (current) {
654d5ac70f0Sopenharmony_ci		list_for_each(pos, &current->include_paths) {
655d5ac70f0Sopenharmony_ci			path = list_entry(pos, struct include_path, list);
656d5ac70f0Sopenharmony_ci			if (!path->dir)
657d5ac70f0Sopenharmony_ci				continue;
658d5ac70f0Sopenharmony_ci
659d5ac70f0Sopenharmony_ci			snprintf(full_path, PATH_MAX, "%s/%s", path->dir, file);
660d5ac70f0Sopenharmony_ci			err = snd_input_stdio_open(inputp, full_path, "r");
661d5ac70f0Sopenharmony_ci			if (err == 0)
662d5ac70f0Sopenharmony_ci				return 0;
663d5ac70f0Sopenharmony_ci		}
664d5ac70f0Sopenharmony_ci		current = current->next;
665d5ac70f0Sopenharmony_ci	}
666d5ac70f0Sopenharmony_ci
667d5ac70f0Sopenharmony_ci	return err;
668d5ac70f0Sopenharmony_ci}
669d5ac70f0Sopenharmony_ci
670d5ac70f0Sopenharmony_ciint _snd_safe_strtoll_base(const char *str, long long *val, int base)
671d5ac70f0Sopenharmony_ci{
672d5ac70f0Sopenharmony_ci	char *end;
673d5ac70f0Sopenharmony_ci	long v;
674d5ac70f0Sopenharmony_ci	if (!*str)
675d5ac70f0Sopenharmony_ci		return -EINVAL;
676d5ac70f0Sopenharmony_ci	errno = 0;
677d5ac70f0Sopenharmony_ci	v = strtoll(str, &end, base);
678d5ac70f0Sopenharmony_ci	if (errno)
679d5ac70f0Sopenharmony_ci		return -errno;
680d5ac70f0Sopenharmony_ci	if (*end)
681d5ac70f0Sopenharmony_ci		return -EINVAL;
682d5ac70f0Sopenharmony_ci	*val = v;
683d5ac70f0Sopenharmony_ci	return 0;
684d5ac70f0Sopenharmony_ci}
685d5ac70f0Sopenharmony_ci
686d5ac70f0Sopenharmony_ciint _snd_safe_strtol_base(const char *str, long *val, int base)
687d5ac70f0Sopenharmony_ci{
688d5ac70f0Sopenharmony_ci	char *end;
689d5ac70f0Sopenharmony_ci	long v;
690d5ac70f0Sopenharmony_ci	if (!*str)
691d5ac70f0Sopenharmony_ci		return -EINVAL;
692d5ac70f0Sopenharmony_ci	errno = 0;
693d5ac70f0Sopenharmony_ci	v = strtol(str, &end, base);
694d5ac70f0Sopenharmony_ci	if (errno)
695d5ac70f0Sopenharmony_ci		return -errno;
696d5ac70f0Sopenharmony_ci	if (*end)
697d5ac70f0Sopenharmony_ci		return -EINVAL;
698d5ac70f0Sopenharmony_ci	*val = v;
699d5ac70f0Sopenharmony_ci	return 0;
700d5ac70f0Sopenharmony_ci}
701d5ac70f0Sopenharmony_ci
702d5ac70f0Sopenharmony_ciint _snd_safe_strtod(const char *str, double *val)
703d5ac70f0Sopenharmony_ci{
704d5ac70f0Sopenharmony_ci	char *end;
705d5ac70f0Sopenharmony_ci	double v;
706d5ac70f0Sopenharmony_ci#ifdef HAVE_USELOCALE
707d5ac70f0Sopenharmony_ci	locale_t saved_locale, c_locale;
708d5ac70f0Sopenharmony_ci#else
709d5ac70f0Sopenharmony_ci	char *saved_locale;
710d5ac70f0Sopenharmony_ci	char locstr[64]; /* enough? */
711d5ac70f0Sopenharmony_ci#endif
712d5ac70f0Sopenharmony_ci	int err;
713d5ac70f0Sopenharmony_ci
714d5ac70f0Sopenharmony_ci	if (!*str)
715d5ac70f0Sopenharmony_ci		return -EINVAL;
716d5ac70f0Sopenharmony_ci#ifdef HAVE_USELOCALE
717d5ac70f0Sopenharmony_ci	c_locale = newlocale(LC_NUMERIC_MASK, "C", 0);
718d5ac70f0Sopenharmony_ci	saved_locale = uselocale(c_locale);
719d5ac70f0Sopenharmony_ci#else
720d5ac70f0Sopenharmony_ci	saved_locale = setlocale(LC_NUMERIC, NULL);
721d5ac70f0Sopenharmony_ci	if (saved_locale) {
722d5ac70f0Sopenharmony_ci		snprintf(locstr, sizeof(locstr), "%s", saved_locale);
723d5ac70f0Sopenharmony_ci		setlocale(LC_NUMERIC, "C");
724d5ac70f0Sopenharmony_ci	}
725d5ac70f0Sopenharmony_ci#endif
726d5ac70f0Sopenharmony_ci	errno = 0;
727d5ac70f0Sopenharmony_ci	v = strtod(str, &end);
728d5ac70f0Sopenharmony_ci	err = -errno;
729d5ac70f0Sopenharmony_ci#ifdef HAVE_USELOCALE
730d5ac70f0Sopenharmony_ci	if (c_locale != (locale_t)0) {
731d5ac70f0Sopenharmony_ci		uselocale(saved_locale);
732d5ac70f0Sopenharmony_ci		freelocale(c_locale);
733d5ac70f0Sopenharmony_ci	}
734d5ac70f0Sopenharmony_ci#else
735d5ac70f0Sopenharmony_ci	if (saved_locale)
736d5ac70f0Sopenharmony_ci		setlocale(LC_NUMERIC, locstr);
737d5ac70f0Sopenharmony_ci#endif
738d5ac70f0Sopenharmony_ci	if (err)
739d5ac70f0Sopenharmony_ci		return err;
740d5ac70f0Sopenharmony_ci	if (*end)
741d5ac70f0Sopenharmony_ci		return -EINVAL;
742d5ac70f0Sopenharmony_ci	*val = v;
743d5ac70f0Sopenharmony_ci	return 0;
744d5ac70f0Sopenharmony_ci}
745d5ac70f0Sopenharmony_ci
746d5ac70f0Sopenharmony_cistatic int get_char(input_t *input)
747d5ac70f0Sopenharmony_ci{
748d5ac70f0Sopenharmony_ci	int c;
749d5ac70f0Sopenharmony_ci	struct filedesc *fd;
750d5ac70f0Sopenharmony_ci	if (input->unget) {
751d5ac70f0Sopenharmony_ci		input->unget = 0;
752d5ac70f0Sopenharmony_ci		return input->ch;
753d5ac70f0Sopenharmony_ci	}
754d5ac70f0Sopenharmony_ci again:
755d5ac70f0Sopenharmony_ci	fd = input->current;
756d5ac70f0Sopenharmony_ci	c = snd_input_getc(fd->in);
757d5ac70f0Sopenharmony_ci	switch (c) {
758d5ac70f0Sopenharmony_ci	case '\n':
759d5ac70f0Sopenharmony_ci		fd->column = 0;
760d5ac70f0Sopenharmony_ci		fd->line++;
761d5ac70f0Sopenharmony_ci		break;
762d5ac70f0Sopenharmony_ci	case '\t':
763d5ac70f0Sopenharmony_ci		fd->column += 8 - fd->column % 8;
764d5ac70f0Sopenharmony_ci		break;
765d5ac70f0Sopenharmony_ci	case EOF:
766d5ac70f0Sopenharmony_ci		if (fd->next) {
767d5ac70f0Sopenharmony_ci			snd_input_close(fd->in);
768d5ac70f0Sopenharmony_ci			free(fd->name);
769d5ac70f0Sopenharmony_ci			input->current = fd->next;
770d5ac70f0Sopenharmony_ci			free(fd);
771d5ac70f0Sopenharmony_ci			goto again;
772d5ac70f0Sopenharmony_ci		}
773d5ac70f0Sopenharmony_ci		return LOCAL_UNEXPECTED_EOF;
774d5ac70f0Sopenharmony_ci	default:
775d5ac70f0Sopenharmony_ci		fd->column++;
776d5ac70f0Sopenharmony_ci		break;
777d5ac70f0Sopenharmony_ci	}
778d5ac70f0Sopenharmony_ci	return (unsigned char)c;
779d5ac70f0Sopenharmony_ci}
780d5ac70f0Sopenharmony_ci
781d5ac70f0Sopenharmony_cistatic void unget_char(int c, input_t *input)
782d5ac70f0Sopenharmony_ci{
783d5ac70f0Sopenharmony_ci	assert(!input->unget);
784d5ac70f0Sopenharmony_ci	input->ch = c;
785d5ac70f0Sopenharmony_ci	input->unget = 1;
786d5ac70f0Sopenharmony_ci}
787d5ac70f0Sopenharmony_ci
788d5ac70f0Sopenharmony_cistatic int get_delimstring(char **string, int delim, input_t *input);
789d5ac70f0Sopenharmony_ci
790d5ac70f0Sopenharmony_cistatic int get_char_skip_comments(input_t *input)
791d5ac70f0Sopenharmony_ci{
792d5ac70f0Sopenharmony_ci	int c;
793d5ac70f0Sopenharmony_ci	while (1) {
794d5ac70f0Sopenharmony_ci		c = get_char(input);
795d5ac70f0Sopenharmony_ci		if (c == '<') {
796d5ac70f0Sopenharmony_ci			char *str;
797d5ac70f0Sopenharmony_ci			snd_input_t *in;
798d5ac70f0Sopenharmony_ci			struct filedesc *fd;
799d5ac70f0Sopenharmony_ci			DIR *dirp;
800d5ac70f0Sopenharmony_ci			int err = get_delimstring(&str, '>', input);
801d5ac70f0Sopenharmony_ci			if (err < 0)
802d5ac70f0Sopenharmony_ci				return err;
803d5ac70f0Sopenharmony_ci
804d5ac70f0Sopenharmony_ci			if (!strncmp(str, "searchdir:", 10)) {
805d5ac70f0Sopenharmony_ci				/* directory to search included files */
806d5ac70f0Sopenharmony_ci				char *tmp = _snd_config_path(str + 10);
807d5ac70f0Sopenharmony_ci				free(str);
808d5ac70f0Sopenharmony_ci				if (tmp == NULL)
809d5ac70f0Sopenharmony_ci					return -ENOMEM;
810d5ac70f0Sopenharmony_ci				str = tmp;
811d5ac70f0Sopenharmony_ci
812d5ac70f0Sopenharmony_ci				dirp = opendir(str);
813d5ac70f0Sopenharmony_ci				if (!dirp) {
814d5ac70f0Sopenharmony_ci					SNDERR("Invalid search dir %s", str);
815d5ac70f0Sopenharmony_ci					free(str);
816d5ac70f0Sopenharmony_ci					return -EINVAL;
817d5ac70f0Sopenharmony_ci				}
818d5ac70f0Sopenharmony_ci				closedir(dirp);
819d5ac70f0Sopenharmony_ci
820d5ac70f0Sopenharmony_ci				err = add_include_path(input->current, str);
821d5ac70f0Sopenharmony_ci				if (err < 0) {
822d5ac70f0Sopenharmony_ci					SNDERR("Cannot add search dir %s", str);
823d5ac70f0Sopenharmony_ci					free(str);
824d5ac70f0Sopenharmony_ci					return err;
825d5ac70f0Sopenharmony_ci				}
826d5ac70f0Sopenharmony_ci				free(str);
827d5ac70f0Sopenharmony_ci				continue;
828d5ac70f0Sopenharmony_ci			}
829d5ac70f0Sopenharmony_ci
830d5ac70f0Sopenharmony_ci			if (!strncmp(str, "confdir:", 8)) {
831d5ac70f0Sopenharmony_ci				/* file in the specified directory */
832d5ac70f0Sopenharmony_ci				char *tmp = _snd_config_path(str + 8);
833d5ac70f0Sopenharmony_ci				free(str);
834d5ac70f0Sopenharmony_ci				if (tmp == NULL)
835d5ac70f0Sopenharmony_ci					return -ENOMEM;
836d5ac70f0Sopenharmony_ci				str = tmp;
837d5ac70f0Sopenharmony_ci				err = snd_input_stdio_open(&in, str, "r");
838d5ac70f0Sopenharmony_ci			} else { /* absolute or relative file path */
839d5ac70f0Sopenharmony_ci				err = input_stdio_open(&in, str, input->current);
840d5ac70f0Sopenharmony_ci			}
841d5ac70f0Sopenharmony_ci
842d5ac70f0Sopenharmony_ci			if (err < 0) {
843d5ac70f0Sopenharmony_ci				SNDERR("Cannot access file %s", str);
844d5ac70f0Sopenharmony_ci				free(str);
845d5ac70f0Sopenharmony_ci				return err;
846d5ac70f0Sopenharmony_ci			}
847d5ac70f0Sopenharmony_ci			fd = malloc(sizeof(*fd));
848d5ac70f0Sopenharmony_ci			if (!fd) {
849d5ac70f0Sopenharmony_ci				free(str);
850d5ac70f0Sopenharmony_ci				return -ENOMEM;
851d5ac70f0Sopenharmony_ci			}
852d5ac70f0Sopenharmony_ci			fd->name = str;
853d5ac70f0Sopenharmony_ci			fd->in = in;
854d5ac70f0Sopenharmony_ci			fd->next = input->current;
855d5ac70f0Sopenharmony_ci			fd->line = 1;
856d5ac70f0Sopenharmony_ci			fd->column = 0;
857d5ac70f0Sopenharmony_ci			INIT_LIST_HEAD(&fd->include_paths);
858d5ac70f0Sopenharmony_ci			input->current = fd;
859d5ac70f0Sopenharmony_ci			continue;
860d5ac70f0Sopenharmony_ci		}
861d5ac70f0Sopenharmony_ci		if (c != '#')
862d5ac70f0Sopenharmony_ci			break;
863d5ac70f0Sopenharmony_ci		while (1) {
864d5ac70f0Sopenharmony_ci			c = get_char(input);
865d5ac70f0Sopenharmony_ci			if (c < 0)
866d5ac70f0Sopenharmony_ci				return c;
867d5ac70f0Sopenharmony_ci			if (c == '\n')
868d5ac70f0Sopenharmony_ci				break;
869d5ac70f0Sopenharmony_ci		}
870d5ac70f0Sopenharmony_ci	}
871d5ac70f0Sopenharmony_ci
872d5ac70f0Sopenharmony_ci	return c;
873d5ac70f0Sopenharmony_ci}
874d5ac70f0Sopenharmony_ci
875d5ac70f0Sopenharmony_ci
876d5ac70f0Sopenharmony_cistatic int get_nonwhite(input_t *input)
877d5ac70f0Sopenharmony_ci{
878d5ac70f0Sopenharmony_ci	int c;
879d5ac70f0Sopenharmony_ci	while (1) {
880d5ac70f0Sopenharmony_ci		c = get_char_skip_comments(input);
881d5ac70f0Sopenharmony_ci		switch (c) {
882d5ac70f0Sopenharmony_ci		case ' ':
883d5ac70f0Sopenharmony_ci		case '\f':
884d5ac70f0Sopenharmony_ci		case '\t':
885d5ac70f0Sopenharmony_ci		case '\n':
886d5ac70f0Sopenharmony_ci		case '\r':
887d5ac70f0Sopenharmony_ci			break;
888d5ac70f0Sopenharmony_ci		default:
889d5ac70f0Sopenharmony_ci			return c;
890d5ac70f0Sopenharmony_ci		}
891d5ac70f0Sopenharmony_ci	}
892d5ac70f0Sopenharmony_ci}
893d5ac70f0Sopenharmony_ci
894d5ac70f0Sopenharmony_cistatic inline int get_hexachar(input_t *input)
895d5ac70f0Sopenharmony_ci{
896d5ac70f0Sopenharmony_ci	int c, num = 0;
897d5ac70f0Sopenharmony_ci
898d5ac70f0Sopenharmony_ci	c = get_char(input);
899d5ac70f0Sopenharmony_ci	if (c >= '0' && c <= '9') num |= (c - '0') << 4;
900d5ac70f0Sopenharmony_ci	else if (c >= 'a' && c <= 'f') num |= (c - 'a') << 4;
901d5ac70f0Sopenharmony_ci	else if (c >= 'A' && c <= 'F') num |= (c - 'A') << 4;
902d5ac70f0Sopenharmony_ci	c = get_char(input);
903d5ac70f0Sopenharmony_ci	if (c >= '0' && c <= '9') num |= (c - '0') << 0;
904d5ac70f0Sopenharmony_ci	else if (c >= 'a' && c <= 'f') num |= (c - 'a') << 0;
905d5ac70f0Sopenharmony_ci	else if (c >= 'A' && c <= 'F') num |= (c - 'A') << 0;
906d5ac70f0Sopenharmony_ci	return num;
907d5ac70f0Sopenharmony_ci}
908d5ac70f0Sopenharmony_ci
909d5ac70f0Sopenharmony_cistatic int get_quotedchar(input_t *input)
910d5ac70f0Sopenharmony_ci{
911d5ac70f0Sopenharmony_ci	int c;
912d5ac70f0Sopenharmony_ci	c = get_char(input);
913d5ac70f0Sopenharmony_ci	switch (c) {
914d5ac70f0Sopenharmony_ci	case 'n':
915d5ac70f0Sopenharmony_ci		return '\n';
916d5ac70f0Sopenharmony_ci	case 't':
917d5ac70f0Sopenharmony_ci		return '\t';
918d5ac70f0Sopenharmony_ci	case 'v':
919d5ac70f0Sopenharmony_ci		return '\v';
920d5ac70f0Sopenharmony_ci	case 'b':
921d5ac70f0Sopenharmony_ci		return '\b';
922d5ac70f0Sopenharmony_ci	case 'r':
923d5ac70f0Sopenharmony_ci		return '\r';
924d5ac70f0Sopenharmony_ci	case 'f':
925d5ac70f0Sopenharmony_ci		return '\f';
926d5ac70f0Sopenharmony_ci	case 'x':
927d5ac70f0Sopenharmony_ci		return get_hexachar(input);
928d5ac70f0Sopenharmony_ci	case '0': case '1': case '2': case '3':
929d5ac70f0Sopenharmony_ci	case '4': case '5': case '6': case '7':
930d5ac70f0Sopenharmony_ci	{
931d5ac70f0Sopenharmony_ci		int num = c - '0';
932d5ac70f0Sopenharmony_ci		int i = 1;
933d5ac70f0Sopenharmony_ci		do {
934d5ac70f0Sopenharmony_ci			c = get_char(input);
935d5ac70f0Sopenharmony_ci			if (c < '0' || c > '7') {
936d5ac70f0Sopenharmony_ci				unget_char(c, input);
937d5ac70f0Sopenharmony_ci				break;
938d5ac70f0Sopenharmony_ci			}
939d5ac70f0Sopenharmony_ci			num = num * 8 + c - '0';
940d5ac70f0Sopenharmony_ci			i++;
941d5ac70f0Sopenharmony_ci		} while (i < 3);
942d5ac70f0Sopenharmony_ci		return num;
943d5ac70f0Sopenharmony_ci	}
944d5ac70f0Sopenharmony_ci	default:
945d5ac70f0Sopenharmony_ci		return c;
946d5ac70f0Sopenharmony_ci	}
947d5ac70f0Sopenharmony_ci}
948d5ac70f0Sopenharmony_ci
949d5ac70f0Sopenharmony_ci#define LOCAL_STR_BUFSIZE	64
950d5ac70f0Sopenharmony_cistruct local_string {
951d5ac70f0Sopenharmony_ci	char *buf;
952d5ac70f0Sopenharmony_ci	size_t alloc;
953d5ac70f0Sopenharmony_ci	size_t idx;
954d5ac70f0Sopenharmony_ci	char tmpbuf[LOCAL_STR_BUFSIZE];
955d5ac70f0Sopenharmony_ci};
956d5ac70f0Sopenharmony_ci
957d5ac70f0Sopenharmony_cistatic void init_local_string(struct local_string *s)
958d5ac70f0Sopenharmony_ci{
959d5ac70f0Sopenharmony_ci	memset(s, 0, sizeof(*s));
960d5ac70f0Sopenharmony_ci	s->buf = s->tmpbuf;
961d5ac70f0Sopenharmony_ci	s->alloc = LOCAL_STR_BUFSIZE;
962d5ac70f0Sopenharmony_ci}
963d5ac70f0Sopenharmony_ci
964d5ac70f0Sopenharmony_cistatic void free_local_string(struct local_string *s)
965d5ac70f0Sopenharmony_ci{
966d5ac70f0Sopenharmony_ci	if (s->buf != s->tmpbuf)
967d5ac70f0Sopenharmony_ci		free(s->buf);
968d5ac70f0Sopenharmony_ci}
969d5ac70f0Sopenharmony_ci
970d5ac70f0Sopenharmony_cistatic int add_char_local_string(struct local_string *s, int c)
971d5ac70f0Sopenharmony_ci{
972d5ac70f0Sopenharmony_ci	if (s->idx >= s->alloc) {
973d5ac70f0Sopenharmony_ci		size_t nalloc = s->alloc * 2;
974d5ac70f0Sopenharmony_ci		if (s->buf == s->tmpbuf) {
975d5ac70f0Sopenharmony_ci			s->buf = malloc(nalloc);
976d5ac70f0Sopenharmony_ci			if (s->buf == NULL)
977d5ac70f0Sopenharmony_ci				return -ENOMEM;
978d5ac70f0Sopenharmony_ci			memcpy(s->buf, s->tmpbuf, s->alloc);
979d5ac70f0Sopenharmony_ci		} else {
980d5ac70f0Sopenharmony_ci			char *ptr = realloc(s->buf, nalloc);
981d5ac70f0Sopenharmony_ci			if (ptr == NULL)
982d5ac70f0Sopenharmony_ci				return -ENOMEM;
983d5ac70f0Sopenharmony_ci			s->buf = ptr;
984d5ac70f0Sopenharmony_ci		}
985d5ac70f0Sopenharmony_ci		s->alloc = nalloc;
986d5ac70f0Sopenharmony_ci	}
987d5ac70f0Sopenharmony_ci	s->buf[s->idx++] = c;
988d5ac70f0Sopenharmony_ci	return 0;
989d5ac70f0Sopenharmony_ci}
990d5ac70f0Sopenharmony_ci
991d5ac70f0Sopenharmony_cistatic char *copy_local_string(struct local_string *s)
992d5ac70f0Sopenharmony_ci{
993d5ac70f0Sopenharmony_ci	char *dst = malloc(s->idx + 1);
994d5ac70f0Sopenharmony_ci	if (dst) {
995d5ac70f0Sopenharmony_ci		memcpy(dst, s->buf, s->idx);
996d5ac70f0Sopenharmony_ci		dst[s->idx] = '\0';
997d5ac70f0Sopenharmony_ci	}
998d5ac70f0Sopenharmony_ci	return dst;
999d5ac70f0Sopenharmony_ci}
1000d5ac70f0Sopenharmony_ci
1001d5ac70f0Sopenharmony_cistatic int get_freestring(char **string, int id, input_t *input)
1002d5ac70f0Sopenharmony_ci{
1003d5ac70f0Sopenharmony_ci	struct local_string str;
1004d5ac70f0Sopenharmony_ci	int c;
1005d5ac70f0Sopenharmony_ci
1006d5ac70f0Sopenharmony_ci	init_local_string(&str);
1007d5ac70f0Sopenharmony_ci	while (1) {
1008d5ac70f0Sopenharmony_ci		c = get_char(input);
1009d5ac70f0Sopenharmony_ci		if (c < 0) {
1010d5ac70f0Sopenharmony_ci			if (c == LOCAL_UNEXPECTED_EOF) {
1011d5ac70f0Sopenharmony_ci				*string = copy_local_string(&str);
1012d5ac70f0Sopenharmony_ci				if (! *string)
1013d5ac70f0Sopenharmony_ci					c = -ENOMEM;
1014d5ac70f0Sopenharmony_ci				else
1015d5ac70f0Sopenharmony_ci					c = 0;
1016d5ac70f0Sopenharmony_ci			}
1017d5ac70f0Sopenharmony_ci			break;
1018d5ac70f0Sopenharmony_ci		}
1019d5ac70f0Sopenharmony_ci		switch (c) {
1020d5ac70f0Sopenharmony_ci		case '.':
1021d5ac70f0Sopenharmony_ci			if (!id)
1022d5ac70f0Sopenharmony_ci				break;
1023d5ac70f0Sopenharmony_ci			/* fall through */
1024d5ac70f0Sopenharmony_ci		case ' ':
1025d5ac70f0Sopenharmony_ci		case '\f':
1026d5ac70f0Sopenharmony_ci		case '\t':
1027d5ac70f0Sopenharmony_ci		case '\n':
1028d5ac70f0Sopenharmony_ci		case '\r':
1029d5ac70f0Sopenharmony_ci		case '=':
1030d5ac70f0Sopenharmony_ci		case ',':
1031d5ac70f0Sopenharmony_ci		case ';':
1032d5ac70f0Sopenharmony_ci		case '{':
1033d5ac70f0Sopenharmony_ci		case '}':
1034d5ac70f0Sopenharmony_ci		case '[':
1035d5ac70f0Sopenharmony_ci		case ']':
1036d5ac70f0Sopenharmony_ci		case '\'':
1037d5ac70f0Sopenharmony_ci		case '"':
1038d5ac70f0Sopenharmony_ci		case '\\':
1039d5ac70f0Sopenharmony_ci		case '#':
1040d5ac70f0Sopenharmony_ci			*string = copy_local_string(&str);
1041d5ac70f0Sopenharmony_ci			if (! *string)
1042d5ac70f0Sopenharmony_ci				c = -ENOMEM;
1043d5ac70f0Sopenharmony_ci			else {
1044d5ac70f0Sopenharmony_ci				unget_char(c, input);
1045d5ac70f0Sopenharmony_ci				c = 0;
1046d5ac70f0Sopenharmony_ci			}
1047d5ac70f0Sopenharmony_ci			goto _out;
1048d5ac70f0Sopenharmony_ci		default:
1049d5ac70f0Sopenharmony_ci			break;
1050d5ac70f0Sopenharmony_ci		}
1051d5ac70f0Sopenharmony_ci		if (add_char_local_string(&str, c) < 0) {
1052d5ac70f0Sopenharmony_ci			c = -ENOMEM;
1053d5ac70f0Sopenharmony_ci			break;
1054d5ac70f0Sopenharmony_ci		}
1055d5ac70f0Sopenharmony_ci	}
1056d5ac70f0Sopenharmony_ci _out:
1057d5ac70f0Sopenharmony_ci	free_local_string(&str);
1058d5ac70f0Sopenharmony_ci	return c;
1059d5ac70f0Sopenharmony_ci}
1060d5ac70f0Sopenharmony_ci
1061d5ac70f0Sopenharmony_cistatic int get_delimstring(char **string, int delim, input_t *input)
1062d5ac70f0Sopenharmony_ci{
1063d5ac70f0Sopenharmony_ci	struct local_string str;
1064d5ac70f0Sopenharmony_ci	int c;
1065d5ac70f0Sopenharmony_ci
1066d5ac70f0Sopenharmony_ci	init_local_string(&str);
1067d5ac70f0Sopenharmony_ci	while (1) {
1068d5ac70f0Sopenharmony_ci		c = get_char(input);
1069d5ac70f0Sopenharmony_ci		if (c < 0)
1070d5ac70f0Sopenharmony_ci			break;
1071d5ac70f0Sopenharmony_ci		if (c == '\\') {
1072d5ac70f0Sopenharmony_ci			c = get_quotedchar(input);
1073d5ac70f0Sopenharmony_ci			if (c < 0)
1074d5ac70f0Sopenharmony_ci				break;
1075d5ac70f0Sopenharmony_ci			if (c == '\n')
1076d5ac70f0Sopenharmony_ci				continue;
1077d5ac70f0Sopenharmony_ci		} else if (c == delim) {
1078d5ac70f0Sopenharmony_ci			*string = copy_local_string(&str);
1079d5ac70f0Sopenharmony_ci			if (! *string)
1080d5ac70f0Sopenharmony_ci				c = -ENOMEM;
1081d5ac70f0Sopenharmony_ci			else
1082d5ac70f0Sopenharmony_ci				c = 0;
1083d5ac70f0Sopenharmony_ci			break;
1084d5ac70f0Sopenharmony_ci		}
1085d5ac70f0Sopenharmony_ci		if (add_char_local_string(&str, c) < 0) {
1086d5ac70f0Sopenharmony_ci			c = -ENOMEM;
1087d5ac70f0Sopenharmony_ci			break;
1088d5ac70f0Sopenharmony_ci		}
1089d5ac70f0Sopenharmony_ci	}
1090d5ac70f0Sopenharmony_ci	 free_local_string(&str);
1091d5ac70f0Sopenharmony_ci	 return c;
1092d5ac70f0Sopenharmony_ci}
1093d5ac70f0Sopenharmony_ci
1094d5ac70f0Sopenharmony_ci/* Return 0 for free string, 1 for delimited string */
1095d5ac70f0Sopenharmony_cistatic int get_string(char **string, int id, input_t *input)
1096d5ac70f0Sopenharmony_ci{
1097d5ac70f0Sopenharmony_ci	int c = get_nonwhite(input), err;
1098d5ac70f0Sopenharmony_ci	if (c < 0)
1099d5ac70f0Sopenharmony_ci		return c;
1100d5ac70f0Sopenharmony_ci	switch (c) {
1101d5ac70f0Sopenharmony_ci	case '=':
1102d5ac70f0Sopenharmony_ci	case ',':
1103d5ac70f0Sopenharmony_ci	case ';':
1104d5ac70f0Sopenharmony_ci	case '.':
1105d5ac70f0Sopenharmony_ci	case '{':
1106d5ac70f0Sopenharmony_ci	case '}':
1107d5ac70f0Sopenharmony_ci	case '[':
1108d5ac70f0Sopenharmony_ci	case ']':
1109d5ac70f0Sopenharmony_ci	case '\\':
1110d5ac70f0Sopenharmony_ci		return LOCAL_UNEXPECTED_CHAR;
1111d5ac70f0Sopenharmony_ci	case '\'':
1112d5ac70f0Sopenharmony_ci	case '"':
1113d5ac70f0Sopenharmony_ci		err = get_delimstring(string, c, input);
1114d5ac70f0Sopenharmony_ci		if (err < 0)
1115d5ac70f0Sopenharmony_ci			return err;
1116d5ac70f0Sopenharmony_ci		return 1;
1117d5ac70f0Sopenharmony_ci	default:
1118d5ac70f0Sopenharmony_ci		unget_char(c, input);
1119d5ac70f0Sopenharmony_ci		err = get_freestring(string, id, input);
1120d5ac70f0Sopenharmony_ci		if (err < 0)
1121d5ac70f0Sopenharmony_ci			return err;
1122d5ac70f0Sopenharmony_ci		return 0;
1123d5ac70f0Sopenharmony_ci	}
1124d5ac70f0Sopenharmony_ci}
1125d5ac70f0Sopenharmony_ci
1126d5ac70f0Sopenharmony_cistatic int _snd_config_make(snd_config_t **config, char **id, snd_config_type_t type)
1127d5ac70f0Sopenharmony_ci{
1128d5ac70f0Sopenharmony_ci	snd_config_t *n;
1129d5ac70f0Sopenharmony_ci	assert(config);
1130d5ac70f0Sopenharmony_ci	n = calloc(1, sizeof(*n));
1131d5ac70f0Sopenharmony_ci	if (n == NULL) {
1132d5ac70f0Sopenharmony_ci		if (*id) {
1133d5ac70f0Sopenharmony_ci			free(*id);
1134d5ac70f0Sopenharmony_ci			*id = NULL;
1135d5ac70f0Sopenharmony_ci		}
1136d5ac70f0Sopenharmony_ci		return -ENOMEM;
1137d5ac70f0Sopenharmony_ci	}
1138d5ac70f0Sopenharmony_ci	if (id) {
1139d5ac70f0Sopenharmony_ci		n->id = *id;
1140d5ac70f0Sopenharmony_ci		*id = NULL;
1141d5ac70f0Sopenharmony_ci	}
1142d5ac70f0Sopenharmony_ci	n->type = type;
1143d5ac70f0Sopenharmony_ci	if (type == SND_CONFIG_TYPE_COMPOUND)
1144d5ac70f0Sopenharmony_ci		INIT_LIST_HEAD(&n->u.compound.fields);
1145d5ac70f0Sopenharmony_ci	*config = n;
1146d5ac70f0Sopenharmony_ci	return 0;
1147d5ac70f0Sopenharmony_ci}
1148d5ac70f0Sopenharmony_ci
1149d5ac70f0Sopenharmony_ci
1150d5ac70f0Sopenharmony_cistatic int _snd_config_make_add(snd_config_t **config, char **id,
1151d5ac70f0Sopenharmony_ci				snd_config_type_t type, snd_config_t *parent)
1152d5ac70f0Sopenharmony_ci{
1153d5ac70f0Sopenharmony_ci	snd_config_t *n;
1154d5ac70f0Sopenharmony_ci	int err;
1155d5ac70f0Sopenharmony_ci	assert(parent->type == SND_CONFIG_TYPE_COMPOUND);
1156d5ac70f0Sopenharmony_ci	err = _snd_config_make(&n, id, type);
1157d5ac70f0Sopenharmony_ci	if (err < 0)
1158d5ac70f0Sopenharmony_ci		return err;
1159d5ac70f0Sopenharmony_ci	n->parent = parent;
1160d5ac70f0Sopenharmony_ci	list_add_tail(&n->list, &parent->u.compound.fields);
1161d5ac70f0Sopenharmony_ci	*config = n;
1162d5ac70f0Sopenharmony_ci	return 0;
1163d5ac70f0Sopenharmony_ci}
1164d5ac70f0Sopenharmony_ci
1165d5ac70f0Sopenharmony_cistatic int _snd_config_search(snd_config_t *config,
1166d5ac70f0Sopenharmony_ci			      const char *id, int len, snd_config_t **result)
1167d5ac70f0Sopenharmony_ci{
1168d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
1169d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, config) {
1170d5ac70f0Sopenharmony_ci		snd_config_t *n = snd_config_iterator_entry(i);
1171d5ac70f0Sopenharmony_ci		if (len < 0) {
1172d5ac70f0Sopenharmony_ci			if (strcmp(n->id, id) != 0)
1173d5ac70f0Sopenharmony_ci				continue;
1174d5ac70f0Sopenharmony_ci		} else if (strlen(n->id) != (size_t) len ||
1175d5ac70f0Sopenharmony_ci			   memcmp(n->id, id, (size_t) len) != 0)
1176d5ac70f0Sopenharmony_ci				continue;
1177d5ac70f0Sopenharmony_ci		if (result)
1178d5ac70f0Sopenharmony_ci			*result = n;
1179d5ac70f0Sopenharmony_ci		return 0;
1180d5ac70f0Sopenharmony_ci	}
1181d5ac70f0Sopenharmony_ci	return -ENOENT;
1182d5ac70f0Sopenharmony_ci}
1183d5ac70f0Sopenharmony_ci
1184d5ac70f0Sopenharmony_cistatic int parse_value(snd_config_t **_n, snd_config_t *parent, input_t *input, char **id, int skip)
1185d5ac70f0Sopenharmony_ci{
1186d5ac70f0Sopenharmony_ci	snd_config_t *n = *_n;
1187d5ac70f0Sopenharmony_ci	char *s;
1188d5ac70f0Sopenharmony_ci	int err;
1189d5ac70f0Sopenharmony_ci
1190d5ac70f0Sopenharmony_ci	err = get_string(&s, 0, input);
1191d5ac70f0Sopenharmony_ci	if (err < 0)
1192d5ac70f0Sopenharmony_ci		return err;
1193d5ac70f0Sopenharmony_ci	if (skip) {
1194d5ac70f0Sopenharmony_ci		free(s);
1195d5ac70f0Sopenharmony_ci		return 0;
1196d5ac70f0Sopenharmony_ci	}
1197d5ac70f0Sopenharmony_ci	if (err == 0 && ((s[0] >= '0' && s[0] <= '9') || s[0] == '-')) {
1198d5ac70f0Sopenharmony_ci		long long i;
1199d5ac70f0Sopenharmony_ci		errno = 0;
1200d5ac70f0Sopenharmony_ci		err = safe_strtoll(s, &i);
1201d5ac70f0Sopenharmony_ci		if (err < 0) {
1202d5ac70f0Sopenharmony_ci			double r;
1203d5ac70f0Sopenharmony_ci			err = safe_strtod(s, &r);
1204d5ac70f0Sopenharmony_ci			if (err >= 0) {
1205d5ac70f0Sopenharmony_ci				free(s);
1206d5ac70f0Sopenharmony_ci				if (n) {
1207d5ac70f0Sopenharmony_ci					if (n->type != SND_CONFIG_TYPE_REAL) {
1208d5ac70f0Sopenharmony_ci						SNDERR("%s is not a real", *id);
1209d5ac70f0Sopenharmony_ci						return -EINVAL;
1210d5ac70f0Sopenharmony_ci					}
1211d5ac70f0Sopenharmony_ci				} else {
1212d5ac70f0Sopenharmony_ci					err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_REAL, parent);
1213d5ac70f0Sopenharmony_ci					if (err < 0)
1214d5ac70f0Sopenharmony_ci						return err;
1215d5ac70f0Sopenharmony_ci				}
1216d5ac70f0Sopenharmony_ci				n->u.real = r;
1217d5ac70f0Sopenharmony_ci				*_n = n;
1218d5ac70f0Sopenharmony_ci				return 0;
1219d5ac70f0Sopenharmony_ci			}
1220d5ac70f0Sopenharmony_ci		} else {
1221d5ac70f0Sopenharmony_ci			free(s);
1222d5ac70f0Sopenharmony_ci			if (n) {
1223d5ac70f0Sopenharmony_ci				if (n->type != SND_CONFIG_TYPE_INTEGER && n->type != SND_CONFIG_TYPE_INTEGER64) {
1224d5ac70f0Sopenharmony_ci					SNDERR("%s is not an integer", *id);
1225d5ac70f0Sopenharmony_ci					return -EINVAL;
1226d5ac70f0Sopenharmony_ci				}
1227d5ac70f0Sopenharmony_ci			} else {
1228d5ac70f0Sopenharmony_ci				if (i <= INT_MAX)
1229d5ac70f0Sopenharmony_ci					err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_INTEGER, parent);
1230d5ac70f0Sopenharmony_ci				else
1231d5ac70f0Sopenharmony_ci					err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_INTEGER64, parent);
1232d5ac70f0Sopenharmony_ci				if (err < 0)
1233d5ac70f0Sopenharmony_ci					return err;
1234d5ac70f0Sopenharmony_ci			}
1235d5ac70f0Sopenharmony_ci			if (n->type == SND_CONFIG_TYPE_INTEGER)
1236d5ac70f0Sopenharmony_ci				n->u.integer = (long) i;
1237d5ac70f0Sopenharmony_ci			else
1238d5ac70f0Sopenharmony_ci				n->u.integer64 = i;
1239d5ac70f0Sopenharmony_ci			*_n = n;
1240d5ac70f0Sopenharmony_ci			return 0;
1241d5ac70f0Sopenharmony_ci		}
1242d5ac70f0Sopenharmony_ci	}
1243d5ac70f0Sopenharmony_ci	if (n) {
1244d5ac70f0Sopenharmony_ci		if (n->type != SND_CONFIG_TYPE_STRING) {
1245d5ac70f0Sopenharmony_ci			SNDERR("%s is not a string", *id);
1246d5ac70f0Sopenharmony_ci			free(s);
1247d5ac70f0Sopenharmony_ci			return -EINVAL;
1248d5ac70f0Sopenharmony_ci		}
1249d5ac70f0Sopenharmony_ci	} else {
1250d5ac70f0Sopenharmony_ci		err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_STRING, parent);
1251d5ac70f0Sopenharmony_ci		if (err < 0)
1252d5ac70f0Sopenharmony_ci			return err;
1253d5ac70f0Sopenharmony_ci	}
1254d5ac70f0Sopenharmony_ci	free(n->u.string);
1255d5ac70f0Sopenharmony_ci	n->u.string = s;
1256d5ac70f0Sopenharmony_ci	*_n = n;
1257d5ac70f0Sopenharmony_ci	return 0;
1258d5ac70f0Sopenharmony_ci}
1259d5ac70f0Sopenharmony_ci
1260d5ac70f0Sopenharmony_cistatic int parse_defs(snd_config_t *parent, input_t *input, int skip, int override);
1261d5ac70f0Sopenharmony_cistatic int parse_array_defs(snd_config_t *farther, input_t *input, int skip, int override);
1262d5ac70f0Sopenharmony_ci
1263d5ac70f0Sopenharmony_cistatic int parse_array_def(snd_config_t *parent, input_t *input, int *idx, int skip, int override)
1264d5ac70f0Sopenharmony_ci{
1265d5ac70f0Sopenharmony_ci	char *id = NULL;
1266d5ac70f0Sopenharmony_ci	int c;
1267d5ac70f0Sopenharmony_ci	int err;
1268d5ac70f0Sopenharmony_ci	snd_config_t *n = NULL;
1269d5ac70f0Sopenharmony_ci
1270d5ac70f0Sopenharmony_ci	if (!skip) {
1271d5ac70f0Sopenharmony_ci		snd_config_t *g;
1272d5ac70f0Sopenharmony_ci		char static_id[12];
1273d5ac70f0Sopenharmony_ci		while (1) {
1274d5ac70f0Sopenharmony_ci			snprintf(static_id, sizeof(static_id), "%i", *idx);
1275d5ac70f0Sopenharmony_ci			if (_snd_config_search(parent, static_id, -1, &g) == 0) {
1276d5ac70f0Sopenharmony_ci				if (override) {
1277d5ac70f0Sopenharmony_ci					snd_config_delete(n);
1278d5ac70f0Sopenharmony_ci				} else {
1279d5ac70f0Sopenharmony_ci					/* merge */
1280d5ac70f0Sopenharmony_ci					(*idx)++;
1281d5ac70f0Sopenharmony_ci					continue;
1282d5ac70f0Sopenharmony_ci				}
1283d5ac70f0Sopenharmony_ci			}
1284d5ac70f0Sopenharmony_ci			break;
1285d5ac70f0Sopenharmony_ci		}
1286d5ac70f0Sopenharmony_ci		id = strdup(static_id);
1287d5ac70f0Sopenharmony_ci		if (id == NULL)
1288d5ac70f0Sopenharmony_ci			return -ENOMEM;
1289d5ac70f0Sopenharmony_ci	}
1290d5ac70f0Sopenharmony_ci	c = get_nonwhite(input);
1291d5ac70f0Sopenharmony_ci	if (c < 0) {
1292d5ac70f0Sopenharmony_ci		err = c;
1293d5ac70f0Sopenharmony_ci		goto __end;
1294d5ac70f0Sopenharmony_ci	}
1295d5ac70f0Sopenharmony_ci	switch (c) {
1296d5ac70f0Sopenharmony_ci	case '{':
1297d5ac70f0Sopenharmony_ci	case '[':
1298d5ac70f0Sopenharmony_ci	{
1299d5ac70f0Sopenharmony_ci		char endchr;
1300d5ac70f0Sopenharmony_ci		if (!skip) {
1301d5ac70f0Sopenharmony_ci			if (n) {
1302d5ac70f0Sopenharmony_ci				if (n->type != SND_CONFIG_TYPE_COMPOUND) {
1303d5ac70f0Sopenharmony_ci					SNDERR("%s is not a compound", id);
1304d5ac70f0Sopenharmony_ci					err = -EINVAL;
1305d5ac70f0Sopenharmony_ci					goto __end;
1306d5ac70f0Sopenharmony_ci				}
1307d5ac70f0Sopenharmony_ci			} else {
1308d5ac70f0Sopenharmony_ci				err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, parent);
1309d5ac70f0Sopenharmony_ci				if (err < 0)
1310d5ac70f0Sopenharmony_ci					goto __end;
1311d5ac70f0Sopenharmony_ci			}
1312d5ac70f0Sopenharmony_ci		}
1313d5ac70f0Sopenharmony_ci		if (c == '{') {
1314d5ac70f0Sopenharmony_ci			err = parse_defs(n, input, skip, override);
1315d5ac70f0Sopenharmony_ci			endchr = '}';
1316d5ac70f0Sopenharmony_ci		} else {
1317d5ac70f0Sopenharmony_ci			err = parse_array_defs(n, input, skip, override);
1318d5ac70f0Sopenharmony_ci			endchr = ']';
1319d5ac70f0Sopenharmony_ci		}
1320d5ac70f0Sopenharmony_ci		c = get_nonwhite(input);
1321d5ac70f0Sopenharmony_ci		if (c < 0) {
1322d5ac70f0Sopenharmony_ci			err = c;
1323d5ac70f0Sopenharmony_ci			goto __end;
1324d5ac70f0Sopenharmony_ci		}
1325d5ac70f0Sopenharmony_ci		if (c != endchr) {
1326d5ac70f0Sopenharmony_ci			if (n)
1327d5ac70f0Sopenharmony_ci				snd_config_delete(n);
1328d5ac70f0Sopenharmony_ci			err = LOCAL_UNEXPECTED_CHAR;
1329d5ac70f0Sopenharmony_ci			goto __end;
1330d5ac70f0Sopenharmony_ci		}
1331d5ac70f0Sopenharmony_ci		break;
1332d5ac70f0Sopenharmony_ci	}
1333d5ac70f0Sopenharmony_ci	default:
1334d5ac70f0Sopenharmony_ci		unget_char(c, input);
1335d5ac70f0Sopenharmony_ci		err = parse_value(&n, parent, input, &id, skip);
1336d5ac70f0Sopenharmony_ci		if (err < 0)
1337d5ac70f0Sopenharmony_ci			goto __end;
1338d5ac70f0Sopenharmony_ci		break;
1339d5ac70f0Sopenharmony_ci	}
1340d5ac70f0Sopenharmony_ci	err = 0;
1341d5ac70f0Sopenharmony_ci      __end:
1342d5ac70f0Sopenharmony_ci	free(id);
1343d5ac70f0Sopenharmony_ci      	return err;
1344d5ac70f0Sopenharmony_ci}
1345d5ac70f0Sopenharmony_ci
1346d5ac70f0Sopenharmony_cistatic int parse_array_defs(snd_config_t *parent, input_t *input, int skip, int override)
1347d5ac70f0Sopenharmony_ci{
1348d5ac70f0Sopenharmony_ci	int idx = 0;
1349d5ac70f0Sopenharmony_ci	while (1) {
1350d5ac70f0Sopenharmony_ci		int c = get_nonwhite(input), err;
1351d5ac70f0Sopenharmony_ci		if (c < 0)
1352d5ac70f0Sopenharmony_ci			return c;
1353d5ac70f0Sopenharmony_ci		unget_char(c, input);
1354d5ac70f0Sopenharmony_ci		if (c == ']')
1355d5ac70f0Sopenharmony_ci			return 0;
1356d5ac70f0Sopenharmony_ci		err = parse_array_def(parent, input, &idx, skip, override);
1357d5ac70f0Sopenharmony_ci		if (err < 0)
1358d5ac70f0Sopenharmony_ci			return err;
1359d5ac70f0Sopenharmony_ci		idx++;
1360d5ac70f0Sopenharmony_ci	}
1361d5ac70f0Sopenharmony_ci	return 0;
1362d5ac70f0Sopenharmony_ci}
1363d5ac70f0Sopenharmony_ci
1364d5ac70f0Sopenharmony_cistatic int parse_def(snd_config_t *parent, input_t *input, int skip, int override)
1365d5ac70f0Sopenharmony_ci{
1366d5ac70f0Sopenharmony_ci	char *id = NULL;
1367d5ac70f0Sopenharmony_ci	int c;
1368d5ac70f0Sopenharmony_ci	int err;
1369d5ac70f0Sopenharmony_ci	snd_config_t *n;
1370d5ac70f0Sopenharmony_ci	enum {MERGE_CREATE, MERGE, OVERRIDE, DONT_OVERRIDE} mode;
1371d5ac70f0Sopenharmony_ci	while (1) {
1372d5ac70f0Sopenharmony_ci		c = get_nonwhite(input);
1373d5ac70f0Sopenharmony_ci		if (c < 0)
1374d5ac70f0Sopenharmony_ci			return c;
1375d5ac70f0Sopenharmony_ci		switch (c) {
1376d5ac70f0Sopenharmony_ci		case '+':
1377d5ac70f0Sopenharmony_ci			mode = MERGE_CREATE;
1378d5ac70f0Sopenharmony_ci			break;
1379d5ac70f0Sopenharmony_ci		case '-':
1380d5ac70f0Sopenharmony_ci			mode = MERGE;
1381d5ac70f0Sopenharmony_ci			break;
1382d5ac70f0Sopenharmony_ci		case '?':
1383d5ac70f0Sopenharmony_ci			mode = DONT_OVERRIDE;
1384d5ac70f0Sopenharmony_ci			break;
1385d5ac70f0Sopenharmony_ci		case '!':
1386d5ac70f0Sopenharmony_ci			mode = OVERRIDE;
1387d5ac70f0Sopenharmony_ci			break;
1388d5ac70f0Sopenharmony_ci		default:
1389d5ac70f0Sopenharmony_ci			mode = !override ? MERGE_CREATE : OVERRIDE;
1390d5ac70f0Sopenharmony_ci			unget_char(c, input);
1391d5ac70f0Sopenharmony_ci		}
1392d5ac70f0Sopenharmony_ci		err = get_string(&id, 1, input);
1393d5ac70f0Sopenharmony_ci		if (err < 0)
1394d5ac70f0Sopenharmony_ci			return err;
1395d5ac70f0Sopenharmony_ci		c = get_nonwhite(input);
1396d5ac70f0Sopenharmony_ci		if (c != '.')
1397d5ac70f0Sopenharmony_ci			break;
1398d5ac70f0Sopenharmony_ci		if (skip) {
1399d5ac70f0Sopenharmony_ci			free(id);
1400d5ac70f0Sopenharmony_ci			continue;
1401d5ac70f0Sopenharmony_ci		}
1402d5ac70f0Sopenharmony_ci		if (_snd_config_search(parent, id, -1, &n) == 0) {
1403d5ac70f0Sopenharmony_ci			if (mode == DONT_OVERRIDE) {
1404d5ac70f0Sopenharmony_ci				skip = 1;
1405d5ac70f0Sopenharmony_ci				free(id);
1406d5ac70f0Sopenharmony_ci				continue;
1407d5ac70f0Sopenharmony_ci			}
1408d5ac70f0Sopenharmony_ci			if (mode != OVERRIDE) {
1409d5ac70f0Sopenharmony_ci				if (n->type != SND_CONFIG_TYPE_COMPOUND) {
1410d5ac70f0Sopenharmony_ci					SNDERR("%s is not a compound", id);
1411d5ac70f0Sopenharmony_ci					return -EINVAL;
1412d5ac70f0Sopenharmony_ci				}
1413d5ac70f0Sopenharmony_ci				n->u.compound.join = true;
1414d5ac70f0Sopenharmony_ci				parent = n;
1415d5ac70f0Sopenharmony_ci				free(id);
1416d5ac70f0Sopenharmony_ci				continue;
1417d5ac70f0Sopenharmony_ci			}
1418d5ac70f0Sopenharmony_ci			snd_config_delete(n);
1419d5ac70f0Sopenharmony_ci		}
1420d5ac70f0Sopenharmony_ci		if (mode == MERGE) {
1421d5ac70f0Sopenharmony_ci			SNDERR("%s does not exists", id);
1422d5ac70f0Sopenharmony_ci			err = -ENOENT;
1423d5ac70f0Sopenharmony_ci			goto __end;
1424d5ac70f0Sopenharmony_ci		}
1425d5ac70f0Sopenharmony_ci		err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, parent);
1426d5ac70f0Sopenharmony_ci		if (err < 0)
1427d5ac70f0Sopenharmony_ci			goto __end;
1428d5ac70f0Sopenharmony_ci		n->u.compound.join = true;
1429d5ac70f0Sopenharmony_ci		parent = n;
1430d5ac70f0Sopenharmony_ci	}
1431d5ac70f0Sopenharmony_ci	if (c == '=') {
1432d5ac70f0Sopenharmony_ci		c = get_nonwhite(input);
1433d5ac70f0Sopenharmony_ci		if (c < 0)
1434d5ac70f0Sopenharmony_ci			return c;
1435d5ac70f0Sopenharmony_ci	}
1436d5ac70f0Sopenharmony_ci	if (!skip) {
1437d5ac70f0Sopenharmony_ci		if (_snd_config_search(parent, id, -1, &n) == 0) {
1438d5ac70f0Sopenharmony_ci			if (mode == DONT_OVERRIDE) {
1439d5ac70f0Sopenharmony_ci				skip = 1;
1440d5ac70f0Sopenharmony_ci				n = NULL;
1441d5ac70f0Sopenharmony_ci			} else if (mode == OVERRIDE) {
1442d5ac70f0Sopenharmony_ci				snd_config_delete(n);
1443d5ac70f0Sopenharmony_ci				n = NULL;
1444d5ac70f0Sopenharmony_ci			}
1445d5ac70f0Sopenharmony_ci		} else {
1446d5ac70f0Sopenharmony_ci			n = NULL;
1447d5ac70f0Sopenharmony_ci			if (mode == MERGE) {
1448d5ac70f0Sopenharmony_ci				SNDERR("%s does not exists", id);
1449d5ac70f0Sopenharmony_ci				err = -ENOENT;
1450d5ac70f0Sopenharmony_ci				goto __end;
1451d5ac70f0Sopenharmony_ci			}
1452d5ac70f0Sopenharmony_ci		}
1453d5ac70f0Sopenharmony_ci	}
1454d5ac70f0Sopenharmony_ci	switch (c) {
1455d5ac70f0Sopenharmony_ci	case '{':
1456d5ac70f0Sopenharmony_ci	case '[':
1457d5ac70f0Sopenharmony_ci	{
1458d5ac70f0Sopenharmony_ci		char endchr;
1459d5ac70f0Sopenharmony_ci		if (!skip) {
1460d5ac70f0Sopenharmony_ci			if (n) {
1461d5ac70f0Sopenharmony_ci				if (n->type != SND_CONFIG_TYPE_COMPOUND) {
1462d5ac70f0Sopenharmony_ci					SNDERR("%s is not a compound", id);
1463d5ac70f0Sopenharmony_ci					err = -EINVAL;
1464d5ac70f0Sopenharmony_ci					goto __end;
1465d5ac70f0Sopenharmony_ci				}
1466d5ac70f0Sopenharmony_ci			} else {
1467d5ac70f0Sopenharmony_ci				err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, parent);
1468d5ac70f0Sopenharmony_ci				if (err < 0)
1469d5ac70f0Sopenharmony_ci					goto __end;
1470d5ac70f0Sopenharmony_ci			}
1471d5ac70f0Sopenharmony_ci		}
1472d5ac70f0Sopenharmony_ci		if (c == '{') {
1473d5ac70f0Sopenharmony_ci			err = parse_defs(n, input, skip, override);
1474d5ac70f0Sopenharmony_ci			endchr = '}';
1475d5ac70f0Sopenharmony_ci		} else {
1476d5ac70f0Sopenharmony_ci			err = parse_array_defs(n, input, skip, override);
1477d5ac70f0Sopenharmony_ci			endchr = ']';
1478d5ac70f0Sopenharmony_ci		}
1479d5ac70f0Sopenharmony_ci		c = get_nonwhite(input);
1480d5ac70f0Sopenharmony_ci		if (c != endchr) {
1481d5ac70f0Sopenharmony_ci			if (n)
1482d5ac70f0Sopenharmony_ci				snd_config_delete(n);
1483d5ac70f0Sopenharmony_ci			err = LOCAL_UNEXPECTED_CHAR;
1484d5ac70f0Sopenharmony_ci			goto __end;
1485d5ac70f0Sopenharmony_ci		}
1486d5ac70f0Sopenharmony_ci		break;
1487d5ac70f0Sopenharmony_ci	}
1488d5ac70f0Sopenharmony_ci	default:
1489d5ac70f0Sopenharmony_ci		unget_char(c, input);
1490d5ac70f0Sopenharmony_ci		err = parse_value(&n, parent, input, &id, skip);
1491d5ac70f0Sopenharmony_ci		if (err < 0)
1492d5ac70f0Sopenharmony_ci			goto __end;
1493d5ac70f0Sopenharmony_ci		break;
1494d5ac70f0Sopenharmony_ci	}
1495d5ac70f0Sopenharmony_ci	c = get_nonwhite(input);
1496d5ac70f0Sopenharmony_ci	switch (c) {
1497d5ac70f0Sopenharmony_ci	case ';':
1498d5ac70f0Sopenharmony_ci	case ',':
1499d5ac70f0Sopenharmony_ci		break;
1500d5ac70f0Sopenharmony_ci	default:
1501d5ac70f0Sopenharmony_ci		unget_char(c, input);
1502d5ac70f0Sopenharmony_ci	}
1503d5ac70f0Sopenharmony_ci      __end:
1504d5ac70f0Sopenharmony_ci	free(id);
1505d5ac70f0Sopenharmony_ci	return err;
1506d5ac70f0Sopenharmony_ci}
1507d5ac70f0Sopenharmony_ci
1508d5ac70f0Sopenharmony_cistatic int parse_defs(snd_config_t *parent, input_t *input, int skip, int override)
1509d5ac70f0Sopenharmony_ci{
1510d5ac70f0Sopenharmony_ci	int c, err;
1511d5ac70f0Sopenharmony_ci	while (1) {
1512d5ac70f0Sopenharmony_ci		c = get_nonwhite(input);
1513d5ac70f0Sopenharmony_ci		if (c < 0)
1514d5ac70f0Sopenharmony_ci			return c == LOCAL_UNEXPECTED_EOF ? 0 : c;
1515d5ac70f0Sopenharmony_ci		unget_char(c, input);
1516d5ac70f0Sopenharmony_ci		if (c == '}')
1517d5ac70f0Sopenharmony_ci			return 0;
1518d5ac70f0Sopenharmony_ci		err = parse_def(parent, input, skip, override);
1519d5ac70f0Sopenharmony_ci		if (err < 0)
1520d5ac70f0Sopenharmony_ci			return err;
1521d5ac70f0Sopenharmony_ci	}
1522d5ac70f0Sopenharmony_ci	return 0;
1523d5ac70f0Sopenharmony_ci}
1524d5ac70f0Sopenharmony_ci
1525d5ac70f0Sopenharmony_cistatic void string_print(char *str, int id, snd_output_t *out)
1526d5ac70f0Sopenharmony_ci{
1527d5ac70f0Sopenharmony_ci	int q;
1528d5ac70f0Sopenharmony_ci	unsigned char *p = (unsigned char *)str;
1529d5ac70f0Sopenharmony_ci	if (!p || !*p) {
1530d5ac70f0Sopenharmony_ci		snd_output_puts(out, "''");
1531d5ac70f0Sopenharmony_ci		return;
1532d5ac70f0Sopenharmony_ci	}
1533d5ac70f0Sopenharmony_ci	if (!id) {
1534d5ac70f0Sopenharmony_ci		switch (*p) {
1535d5ac70f0Sopenharmony_ci		case '0': case '1': case '2': case '3': case '4':
1536d5ac70f0Sopenharmony_ci		case '5': case '6': case '7': case '8': case '9':
1537d5ac70f0Sopenharmony_ci		case '-':
1538d5ac70f0Sopenharmony_ci			goto quoted;
1539d5ac70f0Sopenharmony_ci		}
1540d5ac70f0Sopenharmony_ci	}
1541d5ac70f0Sopenharmony_ci loop:
1542d5ac70f0Sopenharmony_ci	switch (*p) {
1543d5ac70f0Sopenharmony_ci	case 0:
1544d5ac70f0Sopenharmony_ci		goto nonquoted;
1545d5ac70f0Sopenharmony_ci	case ' ':
1546d5ac70f0Sopenharmony_ci	case '=':
1547d5ac70f0Sopenharmony_ci	case ';':
1548d5ac70f0Sopenharmony_ci	case ',':
1549d5ac70f0Sopenharmony_ci	case '.':
1550d5ac70f0Sopenharmony_ci	case '{':
1551d5ac70f0Sopenharmony_ci	case '}':
1552d5ac70f0Sopenharmony_ci	case '[':
1553d5ac70f0Sopenharmony_ci	case ']':
1554d5ac70f0Sopenharmony_ci	case '\'':
1555d5ac70f0Sopenharmony_ci	case '"':
1556d5ac70f0Sopenharmony_ci	case '*':
1557d5ac70f0Sopenharmony_ci	case '#':
1558d5ac70f0Sopenharmony_ci		goto quoted;
1559d5ac70f0Sopenharmony_ci	default:
1560d5ac70f0Sopenharmony_ci		if (*p <= 31 || *p >= 127)
1561d5ac70f0Sopenharmony_ci			goto quoted;
1562d5ac70f0Sopenharmony_ci		p++;
1563d5ac70f0Sopenharmony_ci		goto loop;
1564d5ac70f0Sopenharmony_ci	}
1565d5ac70f0Sopenharmony_ci nonquoted:
1566d5ac70f0Sopenharmony_ci	snd_output_puts(out, str);
1567d5ac70f0Sopenharmony_ci	return;
1568d5ac70f0Sopenharmony_ci quoted:
1569d5ac70f0Sopenharmony_ci	q = strchr(str, '\'') ? '"' : '\'';
1570d5ac70f0Sopenharmony_ci	snd_output_putc(out, q);
1571d5ac70f0Sopenharmony_ci	p = (unsigned char *)str;
1572d5ac70f0Sopenharmony_ci	while (*p) {
1573d5ac70f0Sopenharmony_ci		int c;
1574d5ac70f0Sopenharmony_ci		c = *p;
1575d5ac70f0Sopenharmony_ci		switch (c) {
1576d5ac70f0Sopenharmony_ci		case '\n':
1577d5ac70f0Sopenharmony_ci			snd_output_putc(out, '\\');
1578d5ac70f0Sopenharmony_ci			snd_output_putc(out, 'n');
1579d5ac70f0Sopenharmony_ci			break;
1580d5ac70f0Sopenharmony_ci		case '\t':
1581d5ac70f0Sopenharmony_ci			snd_output_putc(out, '\\');
1582d5ac70f0Sopenharmony_ci			snd_output_putc(out, 't');
1583d5ac70f0Sopenharmony_ci			break;
1584d5ac70f0Sopenharmony_ci		case '\v':
1585d5ac70f0Sopenharmony_ci			snd_output_putc(out, '\\');
1586d5ac70f0Sopenharmony_ci			snd_output_putc(out, 'v');
1587d5ac70f0Sopenharmony_ci			break;
1588d5ac70f0Sopenharmony_ci		case '\b':
1589d5ac70f0Sopenharmony_ci			snd_output_putc(out, '\\');
1590d5ac70f0Sopenharmony_ci			snd_output_putc(out, 'b');
1591d5ac70f0Sopenharmony_ci			break;
1592d5ac70f0Sopenharmony_ci		case '\r':
1593d5ac70f0Sopenharmony_ci			snd_output_putc(out, '\\');
1594d5ac70f0Sopenharmony_ci			snd_output_putc(out, 'r');
1595d5ac70f0Sopenharmony_ci			break;
1596d5ac70f0Sopenharmony_ci		case '\f':
1597d5ac70f0Sopenharmony_ci			snd_output_putc(out, '\\');
1598d5ac70f0Sopenharmony_ci			snd_output_putc(out, 'f');
1599d5ac70f0Sopenharmony_ci			break;
1600d5ac70f0Sopenharmony_ci		default:
1601d5ac70f0Sopenharmony_ci			if (c == q) {
1602d5ac70f0Sopenharmony_ci				snd_output_putc(out, '\\');
1603d5ac70f0Sopenharmony_ci				snd_output_putc(out, c);
1604d5ac70f0Sopenharmony_ci			} else {
1605d5ac70f0Sopenharmony_ci				if (c >= 32 && c <= 126)
1606d5ac70f0Sopenharmony_ci					snd_output_putc(out, c);
1607d5ac70f0Sopenharmony_ci				else
1608d5ac70f0Sopenharmony_ci					snd_output_printf(out, "\\%04o", c);
1609d5ac70f0Sopenharmony_ci			}
1610d5ac70f0Sopenharmony_ci			break;
1611d5ac70f0Sopenharmony_ci		}
1612d5ac70f0Sopenharmony_ci		p++;
1613d5ac70f0Sopenharmony_ci	}
1614d5ac70f0Sopenharmony_ci	snd_output_putc(out, q);
1615d5ac70f0Sopenharmony_ci}
1616d5ac70f0Sopenharmony_ci
1617d5ac70f0Sopenharmony_cistatic void level_print(snd_output_t *out, unsigned int level)
1618d5ac70f0Sopenharmony_ci{
1619d5ac70f0Sopenharmony_ci	char a[level + 1];
1620d5ac70f0Sopenharmony_ci	memset(a, '\t', level);
1621d5ac70f0Sopenharmony_ci	a[level] = '\0';
1622d5ac70f0Sopenharmony_ci	snd_output_puts(out, a);
1623d5ac70f0Sopenharmony_ci}
1624d5ac70f0Sopenharmony_ci
1625d5ac70f0Sopenharmony_cistatic int _snd_config_save_children(snd_config_t *config, snd_output_t *out,
1626d5ac70f0Sopenharmony_ci				     unsigned int level, unsigned int joins,
1627d5ac70f0Sopenharmony_ci				     int array);
1628d5ac70f0Sopenharmony_ci
1629d5ac70f0Sopenharmony_ciint _snd_config_save_node_value(snd_config_t *n, snd_output_t *out,
1630d5ac70f0Sopenharmony_ci				unsigned int level)
1631d5ac70f0Sopenharmony_ci{
1632d5ac70f0Sopenharmony_ci	int err, array;
1633d5ac70f0Sopenharmony_ci	switch (n->type) {
1634d5ac70f0Sopenharmony_ci	case SND_CONFIG_TYPE_INTEGER:
1635d5ac70f0Sopenharmony_ci		snd_output_printf(out, "%ld", n->u.integer);
1636d5ac70f0Sopenharmony_ci		break;
1637d5ac70f0Sopenharmony_ci	case SND_CONFIG_TYPE_INTEGER64:
1638d5ac70f0Sopenharmony_ci		snd_output_printf(out, "%lld", n->u.integer64);
1639d5ac70f0Sopenharmony_ci		break;
1640d5ac70f0Sopenharmony_ci	case SND_CONFIG_TYPE_REAL:
1641d5ac70f0Sopenharmony_ci		snd_output_printf(out, "%-16g", n->u.real);
1642d5ac70f0Sopenharmony_ci		break;
1643d5ac70f0Sopenharmony_ci	case SND_CONFIG_TYPE_STRING:
1644d5ac70f0Sopenharmony_ci		string_print(n->u.string, 0, out);
1645d5ac70f0Sopenharmony_ci		break;
1646d5ac70f0Sopenharmony_ci	case SND_CONFIG_TYPE_POINTER:
1647d5ac70f0Sopenharmony_ci		SNDERR("cannot save runtime pointer type");
1648d5ac70f0Sopenharmony_ci		return -EINVAL;
1649d5ac70f0Sopenharmony_ci	case SND_CONFIG_TYPE_COMPOUND:
1650d5ac70f0Sopenharmony_ci		array = snd_config_is_array(n);
1651d5ac70f0Sopenharmony_ci		snd_output_putc(out, array ? '[' : '{');
1652d5ac70f0Sopenharmony_ci		snd_output_putc(out, '\n');
1653d5ac70f0Sopenharmony_ci		err = _snd_config_save_children(n, out, level + 1, 0, array);
1654d5ac70f0Sopenharmony_ci		if (err < 0)
1655d5ac70f0Sopenharmony_ci			return err;
1656d5ac70f0Sopenharmony_ci		level_print(out, level);
1657d5ac70f0Sopenharmony_ci		snd_output_putc(out, array ? ']' : '}');
1658d5ac70f0Sopenharmony_ci		break;
1659d5ac70f0Sopenharmony_ci	}
1660d5ac70f0Sopenharmony_ci	return 0;
1661d5ac70f0Sopenharmony_ci}
1662d5ac70f0Sopenharmony_ci
1663d5ac70f0Sopenharmony_cistatic void id_print(snd_config_t *n, snd_output_t *out, unsigned int joins)
1664d5ac70f0Sopenharmony_ci{
1665d5ac70f0Sopenharmony_ci	if (joins > 0) {
1666d5ac70f0Sopenharmony_ci		assert(n->parent);
1667d5ac70f0Sopenharmony_ci		id_print(n->parent, out, joins - 1);
1668d5ac70f0Sopenharmony_ci		snd_output_putc(out, '.');
1669d5ac70f0Sopenharmony_ci	}
1670d5ac70f0Sopenharmony_ci	string_print(n->id, 1, out);
1671d5ac70f0Sopenharmony_ci}
1672d5ac70f0Sopenharmony_ci
1673d5ac70f0Sopenharmony_cistatic int _snd_config_save_children(snd_config_t *config, snd_output_t *out,
1674d5ac70f0Sopenharmony_ci				     unsigned int level, unsigned int joins,
1675d5ac70f0Sopenharmony_ci				     int array)
1676d5ac70f0Sopenharmony_ci{
1677d5ac70f0Sopenharmony_ci	int err;
1678d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
1679d5ac70f0Sopenharmony_ci	assert(config && out);
1680d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, config) {
1681d5ac70f0Sopenharmony_ci		snd_config_t *n = snd_config_iterator_entry(i);
1682d5ac70f0Sopenharmony_ci		if (n->type == SND_CONFIG_TYPE_COMPOUND &&
1683d5ac70f0Sopenharmony_ci		    n->u.compound.join) {
1684d5ac70f0Sopenharmony_ci			err = _snd_config_save_children(n, out, level, joins + 1, 0);
1685d5ac70f0Sopenharmony_ci			if (err < 0)
1686d5ac70f0Sopenharmony_ci				return err;
1687d5ac70f0Sopenharmony_ci			continue;
1688d5ac70f0Sopenharmony_ci		}
1689d5ac70f0Sopenharmony_ci		level_print(out, level);
1690d5ac70f0Sopenharmony_ci		if (!array) {
1691d5ac70f0Sopenharmony_ci			id_print(n, out, joins);
1692d5ac70f0Sopenharmony_ci			snd_output_putc(out, ' ');
1693d5ac70f0Sopenharmony_ci#if 0
1694d5ac70f0Sopenharmony_ci			snd_output_putc(out, '=');
1695d5ac70f0Sopenharmony_ci#endif
1696d5ac70f0Sopenharmony_ci		}
1697d5ac70f0Sopenharmony_ci		err = _snd_config_save_node_value(n, out, level);
1698d5ac70f0Sopenharmony_ci		if (err < 0)
1699d5ac70f0Sopenharmony_ci			return err;
1700d5ac70f0Sopenharmony_ci#if 0
1701d5ac70f0Sopenharmony_ci		snd_output_putc(out, ';');
1702d5ac70f0Sopenharmony_ci#endif
1703d5ac70f0Sopenharmony_ci		snd_output_putc(out, '\n');
1704d5ac70f0Sopenharmony_ci	}
1705d5ac70f0Sopenharmony_ci	return 0;
1706d5ac70f0Sopenharmony_ci}
1707d5ac70f0Sopenharmony_ci#endif /* DOC_HIDDEN */
1708d5ac70f0Sopenharmony_ci
1709d5ac70f0Sopenharmony_ci
1710d5ac70f0Sopenharmony_ci/**
1711d5ac70f0Sopenharmony_ci * \brief Substitutes one configuration node to another.
1712d5ac70f0Sopenharmony_ci * \param dst Handle to the destination node.
1713d5ac70f0Sopenharmony_ci * \param src Handle to the source node. Must not be the same as \a dst.
1714d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
1715d5ac70f0Sopenharmony_ci *
1716d5ac70f0Sopenharmony_ci * If both nodes are compounds, the source compound node members will
1717d5ac70f0Sopenharmony_ci * be moved to the destination compound node. The original destination
1718d5ac70f0Sopenharmony_ci * compound node members will be deleted (overwritten).
1719d5ac70f0Sopenharmony_ci *
1720d5ac70f0Sopenharmony_ci * If the destination node is a compound and the source node is
1721d5ac70f0Sopenharmony_ci * an ordinary type, the compound members are deleted (including
1722d5ac70f0Sopenharmony_ci * their contents).
1723d5ac70f0Sopenharmony_ci *
1724d5ac70f0Sopenharmony_ci * Otherwise, the source node's value replaces the destination node's
1725d5ac70f0Sopenharmony_ci * value.
1726d5ac70f0Sopenharmony_ci *
1727d5ac70f0Sopenharmony_ci * In any case, a successful call to this function frees the source
1728d5ac70f0Sopenharmony_ci * node.
1729d5ac70f0Sopenharmony_ci */
1730d5ac70f0Sopenharmony_ciint snd_config_substitute(snd_config_t *dst, snd_config_t *src)
1731d5ac70f0Sopenharmony_ci{
1732d5ac70f0Sopenharmony_ci	assert(dst && src);
1733d5ac70f0Sopenharmony_ci	if (dst->type == SND_CONFIG_TYPE_COMPOUND) {
1734d5ac70f0Sopenharmony_ci		int err = snd_config_delete_compound_members(dst);
1735d5ac70f0Sopenharmony_ci		if (err < 0)
1736d5ac70f0Sopenharmony_ci			return err;
1737d5ac70f0Sopenharmony_ci	}
1738d5ac70f0Sopenharmony_ci	if (dst->type == SND_CONFIG_TYPE_COMPOUND &&
1739d5ac70f0Sopenharmony_ci	    src->type == SND_CONFIG_TYPE_COMPOUND) {	/* overwrite */
1740d5ac70f0Sopenharmony_ci		snd_config_iterator_t i, next;
1741d5ac70f0Sopenharmony_ci		snd_config_for_each(i, next, src) {
1742d5ac70f0Sopenharmony_ci			snd_config_t *n = snd_config_iterator_entry(i);
1743d5ac70f0Sopenharmony_ci			n->parent = dst;
1744d5ac70f0Sopenharmony_ci		}
1745d5ac70f0Sopenharmony_ci		src->u.compound.fields.next->prev = &dst->u.compound.fields;
1746d5ac70f0Sopenharmony_ci		src->u.compound.fields.prev->next = &dst->u.compound.fields;
1747d5ac70f0Sopenharmony_ci	}
1748d5ac70f0Sopenharmony_ci	free(dst->id);
1749d5ac70f0Sopenharmony_ci	if (dst->type == SND_CONFIG_TYPE_STRING)
1750d5ac70f0Sopenharmony_ci		free(dst->u.string);
1751d5ac70f0Sopenharmony_ci	dst->id = src->id;
1752d5ac70f0Sopenharmony_ci	dst->type = src->type;
1753d5ac70f0Sopenharmony_ci	dst->u = src->u;
1754d5ac70f0Sopenharmony_ci	free(src);
1755d5ac70f0Sopenharmony_ci	return 0;
1756d5ac70f0Sopenharmony_ci}
1757d5ac70f0Sopenharmony_ci
1758d5ac70f0Sopenharmony_ci/**
1759d5ac70f0Sopenharmony_ci * \brief Converts an ASCII string to a configuration node type.
1760d5ac70f0Sopenharmony_ci * \param[in] ascii A string containing a configuration node type.
1761d5ac70f0Sopenharmony_ci * \param[out] type The node type corresponding to \a ascii.
1762d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
1763d5ac70f0Sopenharmony_ci *
1764d5ac70f0Sopenharmony_ci * This function recognizes at least the following node types:
1765d5ac70f0Sopenharmony_ci * <dl>
1766d5ac70f0Sopenharmony_ci * <dt>integer<dt>#SND_CONFIG_TYPE_INTEGER
1767d5ac70f0Sopenharmony_ci * <dt>integer64<dt>#SND_CONFIG_TYPE_INTEGER64
1768d5ac70f0Sopenharmony_ci * <dt>real<dt>#SND_CONFIG_TYPE_REAL
1769d5ac70f0Sopenharmony_ci * <dt>string<dt>#SND_CONFIG_TYPE_STRING
1770d5ac70f0Sopenharmony_ci * <dt>compound<dt>#SND_CONFIG_TYPE_COMPOUND
1771d5ac70f0Sopenharmony_ci * </dl>
1772d5ac70f0Sopenharmony_ci *
1773d5ac70f0Sopenharmony_ci * \par Errors:
1774d5ac70f0Sopenharmony_ci * <dl>
1775d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>Unknown note type in \a type.
1776d5ac70f0Sopenharmony_ci * </dl>
1777d5ac70f0Sopenharmony_ci */
1778d5ac70f0Sopenharmony_ciint snd_config_get_type_ascii(const char *ascii, snd_config_type_t *type)
1779d5ac70f0Sopenharmony_ci{
1780d5ac70f0Sopenharmony_ci	assert(ascii && type);
1781d5ac70f0Sopenharmony_ci	if (!strcmp(ascii, "integer")) {
1782d5ac70f0Sopenharmony_ci		*type = SND_CONFIG_TYPE_INTEGER;
1783d5ac70f0Sopenharmony_ci		return 0;
1784d5ac70f0Sopenharmony_ci	}
1785d5ac70f0Sopenharmony_ci	if (!strcmp(ascii, "integer64")) {
1786d5ac70f0Sopenharmony_ci		*type = SND_CONFIG_TYPE_INTEGER64;
1787d5ac70f0Sopenharmony_ci		return 0;
1788d5ac70f0Sopenharmony_ci	}
1789d5ac70f0Sopenharmony_ci	if (!strcmp(ascii, "real")) {
1790d5ac70f0Sopenharmony_ci		*type = SND_CONFIG_TYPE_REAL;
1791d5ac70f0Sopenharmony_ci		return 0;
1792d5ac70f0Sopenharmony_ci	}
1793d5ac70f0Sopenharmony_ci	if (!strcmp(ascii, "string")) {
1794d5ac70f0Sopenharmony_ci		*type = SND_CONFIG_TYPE_STRING;
1795d5ac70f0Sopenharmony_ci		return 0;
1796d5ac70f0Sopenharmony_ci	}
1797d5ac70f0Sopenharmony_ci	if (!strcmp(ascii, "compound")) {
1798d5ac70f0Sopenharmony_ci		*type = SND_CONFIG_TYPE_COMPOUND;
1799d5ac70f0Sopenharmony_ci		return 0;
1800d5ac70f0Sopenharmony_ci	}
1801d5ac70f0Sopenharmony_ci	return -EINVAL;
1802d5ac70f0Sopenharmony_ci}
1803d5ac70f0Sopenharmony_ci
1804d5ac70f0Sopenharmony_ci/**
1805d5ac70f0Sopenharmony_ci * \brief Returns the type of a configuration node.
1806d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node.
1807d5ac70f0Sopenharmony_ci * \return The node's type.
1808d5ac70f0Sopenharmony_ci *
1809d5ac70f0Sopenharmony_ci * \par Conforming to:
1810d5ac70f0Sopenharmony_ci * LSB 3.2
1811d5ac70f0Sopenharmony_ci */
1812d5ac70f0Sopenharmony_cisnd_config_type_t snd_config_get_type(const snd_config_t *config)
1813d5ac70f0Sopenharmony_ci{
1814d5ac70f0Sopenharmony_ci	return config->type;
1815d5ac70f0Sopenharmony_ci}
1816d5ac70f0Sopenharmony_ci
1817d5ac70f0Sopenharmony_cistatic int check_array_item(const char *id, int index)
1818d5ac70f0Sopenharmony_ci{
1819d5ac70f0Sopenharmony_ci	const char *p;
1820d5ac70f0Sopenharmony_ci	long val;
1821d5ac70f0Sopenharmony_ci
1822d5ac70f0Sopenharmony_ci	for (p = id; *p; p++) {
1823d5ac70f0Sopenharmony_ci		if (*p < '0' || *p > '9')
1824d5ac70f0Sopenharmony_ci			return 0;
1825d5ac70f0Sopenharmony_ci	}
1826d5ac70f0Sopenharmony_ci
1827d5ac70f0Sopenharmony_ci	if (safe_strtol(id, &val))
1828d5ac70f0Sopenharmony_ci		return 0;
1829d5ac70f0Sopenharmony_ci	return val == index;
1830d5ac70f0Sopenharmony_ci}
1831d5ac70f0Sopenharmony_ci
1832d5ac70f0Sopenharmony_ci/**
1833d5ac70f0Sopenharmony_ci * \brief Returns if the compound is an array (and count of items).
1834d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node.
1835d5ac70f0Sopenharmony_ci * \return A count of items in array, zero when the compound is not an array,
1836d5ac70f0Sopenharmony_ci *         otherwise a negative error code.
1837d5ac70f0Sopenharmony_ci */
1838d5ac70f0Sopenharmony_ciint snd_config_is_array(const snd_config_t *config)
1839d5ac70f0Sopenharmony_ci{
1840d5ac70f0Sopenharmony_ci	int idx;
1841d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
1842d5ac70f0Sopenharmony_ci	snd_config_t *node;
1843d5ac70f0Sopenharmony_ci
1844d5ac70f0Sopenharmony_ci	assert(config);
1845d5ac70f0Sopenharmony_ci	if (config->type != SND_CONFIG_TYPE_COMPOUND)
1846d5ac70f0Sopenharmony_ci		return -EINVAL;
1847d5ac70f0Sopenharmony_ci	idx = 0;
1848d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, config) {
1849d5ac70f0Sopenharmony_ci		node = snd_config_iterator_entry(i);
1850d5ac70f0Sopenharmony_ci		if (!check_array_item(node->id, idx))
1851d5ac70f0Sopenharmony_ci			return 0;
1852d5ac70f0Sopenharmony_ci		idx++;
1853d5ac70f0Sopenharmony_ci	}
1854d5ac70f0Sopenharmony_ci	return idx;
1855d5ac70f0Sopenharmony_ci}
1856d5ac70f0Sopenharmony_ci
1857d5ac70f0Sopenharmony_ci/**
1858d5ac70f0Sopenharmony_ci * \brief Returns if the compound has no fields (is empty).
1859d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node.
1860d5ac70f0Sopenharmony_ci * \return A positive value when true, zero when false, otherwise a negative error code.
1861d5ac70f0Sopenharmony_ci */
1862d5ac70f0Sopenharmony_ciint snd_config_is_empty(const snd_config_t *config)
1863d5ac70f0Sopenharmony_ci{
1864d5ac70f0Sopenharmony_ci	assert(config);
1865d5ac70f0Sopenharmony_ci	if (config->type != SND_CONFIG_TYPE_COMPOUND)
1866d5ac70f0Sopenharmony_ci		return -EINVAL;
1867d5ac70f0Sopenharmony_ci	return list_empty(&config->u.compound.fields);
1868d5ac70f0Sopenharmony_ci}
1869d5ac70f0Sopenharmony_ci
1870d5ac70f0Sopenharmony_ci/**
1871d5ac70f0Sopenharmony_ci * \brief Returns the id of a configuration node.
1872d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration node.
1873d5ac70f0Sopenharmony_ci * \param[out] id The function puts the pointer to the id string at the
1874d5ac70f0Sopenharmony_ci *                address specified by \a id.
1875d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
1876d5ac70f0Sopenharmony_ci *
1877d5ac70f0Sopenharmony_ci * The returned string is owned by the configuration node; the application
1878d5ac70f0Sopenharmony_ci * must not modify or delete it, and the string becomes invalid when the
1879d5ac70f0Sopenharmony_ci * node's id changes or when the node is freed.
1880d5ac70f0Sopenharmony_ci *
1881d5ac70f0Sopenharmony_ci * If the node does not have an id, \a *id is set to \c NULL.
1882d5ac70f0Sopenharmony_ci *
1883d5ac70f0Sopenharmony_ci * \par Conforming to:
1884d5ac70f0Sopenharmony_ci * LSB 3.2
1885d5ac70f0Sopenharmony_ci */
1886d5ac70f0Sopenharmony_ciint snd_config_get_id(const snd_config_t *config, const char **id)
1887d5ac70f0Sopenharmony_ci{
1888d5ac70f0Sopenharmony_ci	assert(config && id);
1889d5ac70f0Sopenharmony_ci	*id = config->id;
1890d5ac70f0Sopenharmony_ci	return 0;
1891d5ac70f0Sopenharmony_ci}
1892d5ac70f0Sopenharmony_ci
1893d5ac70f0Sopenharmony_ci/**
1894d5ac70f0Sopenharmony_ci * \brief Sets the id of a configuration node.
1895d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node.
1896d5ac70f0Sopenharmony_ci * \param id The new node id, must not be \c NULL.
1897d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
1898d5ac70f0Sopenharmony_ci *
1899d5ac70f0Sopenharmony_ci * This function stores a copy of \a id in the node.
1900d5ac70f0Sopenharmony_ci *
1901d5ac70f0Sopenharmony_ci * \par Errors:
1902d5ac70f0Sopenharmony_ci * <dl>
1903d5ac70f0Sopenharmony_ci * <dt>-EEXIST<dd>One of \a config's siblings already has the id \a id.
1904d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>The id of a node with a parent cannot be set to \c NULL.
1905d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory.
1906d5ac70f0Sopenharmony_ci * </dl>
1907d5ac70f0Sopenharmony_ci */
1908d5ac70f0Sopenharmony_ciint snd_config_set_id(snd_config_t *config, const char *id)
1909d5ac70f0Sopenharmony_ci{
1910d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
1911d5ac70f0Sopenharmony_ci	char *new_id;
1912d5ac70f0Sopenharmony_ci	assert(config);
1913d5ac70f0Sopenharmony_ci	if (id) {
1914d5ac70f0Sopenharmony_ci		if (config->parent) {
1915d5ac70f0Sopenharmony_ci			snd_config_for_each(i, next, config->parent) {
1916d5ac70f0Sopenharmony_ci				snd_config_t *n = snd_config_iterator_entry(i);
1917d5ac70f0Sopenharmony_ci				if (n != config && strcmp(id, n->id) == 0)
1918d5ac70f0Sopenharmony_ci					return -EEXIST;
1919d5ac70f0Sopenharmony_ci			}
1920d5ac70f0Sopenharmony_ci		}
1921d5ac70f0Sopenharmony_ci		new_id = strdup(id);
1922d5ac70f0Sopenharmony_ci		if (!new_id)
1923d5ac70f0Sopenharmony_ci			return -ENOMEM;
1924d5ac70f0Sopenharmony_ci	} else {
1925d5ac70f0Sopenharmony_ci		if (config->parent)
1926d5ac70f0Sopenharmony_ci			return -EINVAL;
1927d5ac70f0Sopenharmony_ci		new_id = NULL;
1928d5ac70f0Sopenharmony_ci	}
1929d5ac70f0Sopenharmony_ci	free(config->id);
1930d5ac70f0Sopenharmony_ci	config->id = new_id;
1931d5ac70f0Sopenharmony_ci	return 0;
1932d5ac70f0Sopenharmony_ci}
1933d5ac70f0Sopenharmony_ci
1934d5ac70f0Sopenharmony_ci/**
1935d5ac70f0Sopenharmony_ci * \brief Creates a top level configuration node.
1936d5ac70f0Sopenharmony_ci * \param[out] config Handle to the new node.
1937d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
1938d5ac70f0Sopenharmony_ci *
1939d5ac70f0Sopenharmony_ci * The returned node is an empty compound node without a parent and
1940d5ac70f0Sopenharmony_ci * without an id.
1941d5ac70f0Sopenharmony_ci *
1942d5ac70f0Sopenharmony_ci * \par Errors:
1943d5ac70f0Sopenharmony_ci * <dl>
1944d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory.
1945d5ac70f0Sopenharmony_ci * </dl>
1946d5ac70f0Sopenharmony_ci *
1947d5ac70f0Sopenharmony_ci * \par Conforming to:
1948d5ac70f0Sopenharmony_ci * LSB 3.2
1949d5ac70f0Sopenharmony_ci */
1950d5ac70f0Sopenharmony_ciint snd_config_top(snd_config_t **config)
1951d5ac70f0Sopenharmony_ci{
1952d5ac70f0Sopenharmony_ci	assert(config);
1953d5ac70f0Sopenharmony_ci	return _snd_config_make(config, 0, SND_CONFIG_TYPE_COMPOUND);
1954d5ac70f0Sopenharmony_ci}
1955d5ac70f0Sopenharmony_ci
1956d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN
1957d5ac70f0Sopenharmony_ciint _snd_config_load_with_include(snd_config_t *config, snd_input_t *in,
1958d5ac70f0Sopenharmony_ci				  int override, const char * const *include_paths)
1959d5ac70f0Sopenharmony_ci{
1960d5ac70f0Sopenharmony_ci	int err;
1961d5ac70f0Sopenharmony_ci	input_t input;
1962d5ac70f0Sopenharmony_ci	struct filedesc *fd, *fd_next;
1963d5ac70f0Sopenharmony_ci
1964d5ac70f0Sopenharmony_ci	assert(config && in);
1965d5ac70f0Sopenharmony_ci	fd = malloc(sizeof(*fd));
1966d5ac70f0Sopenharmony_ci	if (!fd)
1967d5ac70f0Sopenharmony_ci		return -ENOMEM;
1968d5ac70f0Sopenharmony_ci	fd->name = NULL;
1969d5ac70f0Sopenharmony_ci	fd->in = in;
1970d5ac70f0Sopenharmony_ci	fd->line = 1;
1971d5ac70f0Sopenharmony_ci	fd->column = 0;
1972d5ac70f0Sopenharmony_ci	fd->next = NULL;
1973d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&fd->include_paths);
1974d5ac70f0Sopenharmony_ci	if (include_paths) {
1975d5ac70f0Sopenharmony_ci		for (; *include_paths; include_paths++) {
1976d5ac70f0Sopenharmony_ci			err = add_include_path(fd, *include_paths);
1977d5ac70f0Sopenharmony_ci			if (err < 0)
1978d5ac70f0Sopenharmony_ci				goto _end;
1979d5ac70f0Sopenharmony_ci		}
1980d5ac70f0Sopenharmony_ci	} else {
1981d5ac70f0Sopenharmony_ci		err = add_include_path(fd, snd_config_topdir());
1982d5ac70f0Sopenharmony_ci		if (err < 0)
1983d5ac70f0Sopenharmony_ci			goto _end;
1984d5ac70f0Sopenharmony_ci	}
1985d5ac70f0Sopenharmony_ci	input.current = fd;
1986d5ac70f0Sopenharmony_ci	input.unget = 0;
1987d5ac70f0Sopenharmony_ci	err = parse_defs(config, &input, 0, override);
1988d5ac70f0Sopenharmony_ci	fd = input.current;
1989d5ac70f0Sopenharmony_ci	if (err < 0) {
1990d5ac70f0Sopenharmony_ci		const char *str;
1991d5ac70f0Sopenharmony_ci		switch (err) {
1992d5ac70f0Sopenharmony_ci		case LOCAL_UNTERMINATED_STRING:
1993d5ac70f0Sopenharmony_ci			str = "Unterminated string";
1994d5ac70f0Sopenharmony_ci			err = -EINVAL;
1995d5ac70f0Sopenharmony_ci			break;
1996d5ac70f0Sopenharmony_ci		case LOCAL_UNTERMINATED_QUOTE:
1997d5ac70f0Sopenharmony_ci			str = "Unterminated quote";
1998d5ac70f0Sopenharmony_ci			err = -EINVAL;
1999d5ac70f0Sopenharmony_ci			break;
2000d5ac70f0Sopenharmony_ci		case LOCAL_UNEXPECTED_CHAR:
2001d5ac70f0Sopenharmony_ci			str = "Unexpected char";
2002d5ac70f0Sopenharmony_ci			err = -EINVAL;
2003d5ac70f0Sopenharmony_ci			break;
2004d5ac70f0Sopenharmony_ci		case LOCAL_UNEXPECTED_EOF:
2005d5ac70f0Sopenharmony_ci			str = "Unexpected end of file";
2006d5ac70f0Sopenharmony_ci			err = -EINVAL;
2007d5ac70f0Sopenharmony_ci			break;
2008d5ac70f0Sopenharmony_ci		default:
2009d5ac70f0Sopenharmony_ci			str = strerror(-err);
2010d5ac70f0Sopenharmony_ci			break;
2011d5ac70f0Sopenharmony_ci		}
2012d5ac70f0Sopenharmony_ci		SNDERR("%s:%d:%d:%s", fd->name ? fd->name : "_toplevel_", fd->line, fd->column, str);
2013d5ac70f0Sopenharmony_ci		goto _end;
2014d5ac70f0Sopenharmony_ci	}
2015d5ac70f0Sopenharmony_ci	err = get_char(&input);
2016d5ac70f0Sopenharmony_ci	fd = input.current;
2017d5ac70f0Sopenharmony_ci	if (err != LOCAL_UNEXPECTED_EOF) {
2018d5ac70f0Sopenharmony_ci		SNDERR("%s:%d:%d:Unexpected }", fd->name ? fd->name : "", fd->line, fd->column);
2019d5ac70f0Sopenharmony_ci		err = -EINVAL;
2020d5ac70f0Sopenharmony_ci		goto _end;
2021d5ac70f0Sopenharmony_ci	}
2022d5ac70f0Sopenharmony_ci	err = 0;
2023d5ac70f0Sopenharmony_ci _end:
2024d5ac70f0Sopenharmony_ci	while (fd->next) {
2025d5ac70f0Sopenharmony_ci		fd_next = fd->next;
2026d5ac70f0Sopenharmony_ci		snd_input_close(fd->in);
2027d5ac70f0Sopenharmony_ci		free(fd->name);
2028d5ac70f0Sopenharmony_ci		free_include_paths(fd);
2029d5ac70f0Sopenharmony_ci		free(fd);
2030d5ac70f0Sopenharmony_ci		fd = fd_next;
2031d5ac70f0Sopenharmony_ci	}
2032d5ac70f0Sopenharmony_ci
2033d5ac70f0Sopenharmony_ci	free_include_paths(fd);
2034d5ac70f0Sopenharmony_ci	free(fd);
2035d5ac70f0Sopenharmony_ci	return err;
2036d5ac70f0Sopenharmony_ci}
2037d5ac70f0Sopenharmony_ci#endif
2038d5ac70f0Sopenharmony_ci
2039d5ac70f0Sopenharmony_ci/**
2040d5ac70f0Sopenharmony_ci * \brief Loads a configuration tree.
2041d5ac70f0Sopenharmony_ci * \param config Handle to a top level configuration node.
2042d5ac70f0Sopenharmony_ci * \param in Input handle to read the configuration from.
2043d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2044d5ac70f0Sopenharmony_ci *
2045d5ac70f0Sopenharmony_ci * The definitions loaded from the input are added to \a config, which
2046d5ac70f0Sopenharmony_ci * must be a compound node.
2047d5ac70f0Sopenharmony_ci *
2048d5ac70f0Sopenharmony_ci * \par Errors:
2049d5ac70f0Sopenharmony_ci * Any errors encountered when parsing the input or returned by hooks or
2050d5ac70f0Sopenharmony_ci * functions.
2051d5ac70f0Sopenharmony_ci *
2052d5ac70f0Sopenharmony_ci * \par Conforming to:
2053d5ac70f0Sopenharmony_ci * LSB 3.2
2054d5ac70f0Sopenharmony_ci */
2055d5ac70f0Sopenharmony_ciint snd_config_load(snd_config_t *config, snd_input_t *in)
2056d5ac70f0Sopenharmony_ci{
2057d5ac70f0Sopenharmony_ci	return _snd_config_load_with_include(config, in, 0, NULL);
2058d5ac70f0Sopenharmony_ci}
2059d5ac70f0Sopenharmony_ci
2060d5ac70f0Sopenharmony_ci/**
2061d5ac70f0Sopenharmony_ci * \brief Loads a configuration tree from a string.
2062d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the configuration
2063d5ac70f0Sopenharmony_ci *	       node loaded from the file(s) at the address specified
2064d5ac70f0Sopenharmony_ci *             by \a config.
2065d5ac70f0Sopenharmony_ci * \param[in] s String with the ASCII configuration
2066d5ac70f0Sopenharmony_ci * \param[in] size String size, if zero, a C string is expected (with termination)
2067d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2068d5ac70f0Sopenharmony_ci *
2069d5ac70f0Sopenharmony_ci * The definitions loaded from the string are put to \a config, which
2070d5ac70f0Sopenharmony_ci * is created as a new top node.
2071d5ac70f0Sopenharmony_ci *
2072d5ac70f0Sopenharmony_ci * \par Errors:
2073d5ac70f0Sopenharmony_ci * Any errors encountered when parsing the input or returned by hooks or
2074d5ac70f0Sopenharmony_ci * functions.
2075d5ac70f0Sopenharmony_ci */
2076d5ac70f0Sopenharmony_ciint snd_config_load_string(snd_config_t **config, const char *s, size_t size)
2077d5ac70f0Sopenharmony_ci{
2078d5ac70f0Sopenharmony_ci	snd_input_t *input;
2079d5ac70f0Sopenharmony_ci	snd_config_t *dst;
2080d5ac70f0Sopenharmony_ci	int err;
2081d5ac70f0Sopenharmony_ci
2082d5ac70f0Sopenharmony_ci	assert(config && s);
2083d5ac70f0Sopenharmony_ci	if (size == 0)
2084d5ac70f0Sopenharmony_ci		size = strlen(s);
2085d5ac70f0Sopenharmony_ci	err = snd_input_buffer_open(&input, s, size);
2086d5ac70f0Sopenharmony_ci	if (err < 0)
2087d5ac70f0Sopenharmony_ci		return err;
2088d5ac70f0Sopenharmony_ci	err = snd_config_top(&dst);
2089d5ac70f0Sopenharmony_ci	if (err < 0) {
2090d5ac70f0Sopenharmony_ci		snd_input_close(input);
2091d5ac70f0Sopenharmony_ci		return err;
2092d5ac70f0Sopenharmony_ci	}
2093d5ac70f0Sopenharmony_ci	err = snd_config_load(dst, input);
2094d5ac70f0Sopenharmony_ci	snd_input_close(input);
2095d5ac70f0Sopenharmony_ci	if (err < 0) {
2096d5ac70f0Sopenharmony_ci		snd_config_delete(dst);
2097d5ac70f0Sopenharmony_ci		return err;
2098d5ac70f0Sopenharmony_ci	}
2099d5ac70f0Sopenharmony_ci	*config = dst;
2100d5ac70f0Sopenharmony_ci	return 0;
2101d5ac70f0Sopenharmony_ci}
2102d5ac70f0Sopenharmony_ci
2103d5ac70f0Sopenharmony_ci/**
2104d5ac70f0Sopenharmony_ci * \brief Loads a configuration tree and overrides existing configuration nodes.
2105d5ac70f0Sopenharmony_ci * \param config Handle to a top level configuration node.
2106d5ac70f0Sopenharmony_ci * \param in Input handle to read the configuration from.
2107d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2108d5ac70f0Sopenharmony_ci *
2109d5ac70f0Sopenharmony_ci * This function loads definitions from \a in into \a config like
2110d5ac70f0Sopenharmony_ci * #snd_config_load, but the default mode for input nodes is 'override'
2111d5ac70f0Sopenharmony_ci * (!) instead of 'merge+create' (+).
2112d5ac70f0Sopenharmony_ci */
2113d5ac70f0Sopenharmony_ciint snd_config_load_override(snd_config_t *config, snd_input_t *in)
2114d5ac70f0Sopenharmony_ci{
2115d5ac70f0Sopenharmony_ci	return _snd_config_load_with_include(config, in, 1, NULL);
2116d5ac70f0Sopenharmony_ci}
2117d5ac70f0Sopenharmony_ci
2118d5ac70f0Sopenharmony_ci/**
2119d5ac70f0Sopenharmony_ci * \brief Adds a child to a compound configuration node.
2120d5ac70f0Sopenharmony_ci * \param parent Handle to a compound configuration node.
2121d5ac70f0Sopenharmony_ci * \param child Handle to the configuration node to be added.
2122d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2123d5ac70f0Sopenharmony_ci *
2124d5ac70f0Sopenharmony_ci * This function makes the node \a child a child of the node \a parent.
2125d5ac70f0Sopenharmony_ci *
2126d5ac70f0Sopenharmony_ci * The parent node then owns the child node, i.e., the child node gets
2127d5ac70f0Sopenharmony_ci * deleted together with its parent.
2128d5ac70f0Sopenharmony_ci *
2129d5ac70f0Sopenharmony_ci * \a child must have an id.
2130d5ac70f0Sopenharmony_ci *
2131d5ac70f0Sopenharmony_ci * \par Errors:
2132d5ac70f0Sopenharmony_ci * <dl>
2133d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a child does not have an id.
2134d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a child already has a parent.
2135d5ac70f0Sopenharmony_ci * <dt>-EEXIST<dd>\a parent already contains a child node with the same
2136d5ac70f0Sopenharmony_ci *                id as \a child.
2137d5ac70f0Sopenharmony_ci * </dl>
2138d5ac70f0Sopenharmony_ci *
2139d5ac70f0Sopenharmony_ci * \par Conforming to:
2140d5ac70f0Sopenharmony_ci * LSB 3.2
2141d5ac70f0Sopenharmony_ci */
2142d5ac70f0Sopenharmony_ciint snd_config_add(snd_config_t *parent, snd_config_t *child)
2143d5ac70f0Sopenharmony_ci{
2144d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
2145d5ac70f0Sopenharmony_ci	assert(parent && child);
2146d5ac70f0Sopenharmony_ci	if (!child->id || child->parent)
2147d5ac70f0Sopenharmony_ci		return -EINVAL;
2148d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, parent) {
2149d5ac70f0Sopenharmony_ci		snd_config_t *n = snd_config_iterator_entry(i);
2150d5ac70f0Sopenharmony_ci		if (strcmp(child->id, n->id) == 0)
2151d5ac70f0Sopenharmony_ci			return -EEXIST;
2152d5ac70f0Sopenharmony_ci	}
2153d5ac70f0Sopenharmony_ci	child->parent = parent;
2154d5ac70f0Sopenharmony_ci	list_add_tail(&child->list, &parent->u.compound.fields);
2155d5ac70f0Sopenharmony_ci	return 0;
2156d5ac70f0Sopenharmony_ci}
2157d5ac70f0Sopenharmony_ci
2158d5ac70f0Sopenharmony_ci/**
2159d5ac70f0Sopenharmony_ci * \brief Adds a child after another child configuration node.
2160d5ac70f0Sopenharmony_ci * \param after Handle to the start configuration node.
2161d5ac70f0Sopenharmony_ci * \param child Handle to the configuration node to be added.
2162d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2163d5ac70f0Sopenharmony_ci *
2164d5ac70f0Sopenharmony_ci * This function makes the node \a child a child of the parent of
2165d5ac70f0Sopenharmony_ci * the node \a after.
2166d5ac70f0Sopenharmony_ci *
2167d5ac70f0Sopenharmony_ci * The parent node then owns the child node, i.e., the child node gets
2168d5ac70f0Sopenharmony_ci * deleted together with its parent.
2169d5ac70f0Sopenharmony_ci *
2170d5ac70f0Sopenharmony_ci * \a child must have an id.
2171d5ac70f0Sopenharmony_ci *
2172d5ac70f0Sopenharmony_ci * \par Errors:
2173d5ac70f0Sopenharmony_ci * <dl>
2174d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a child does not have an id.
2175d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a child already has a parent.
2176d5ac70f0Sopenharmony_ci * <dt>-EEXIST<dd>\a parent already contains a child node with the same
2177d5ac70f0Sopenharmony_ci *                id as \a child.
2178d5ac70f0Sopenharmony_ci * </dl>
2179d5ac70f0Sopenharmony_ci */
2180d5ac70f0Sopenharmony_ciint snd_config_add_after(snd_config_t *after, snd_config_t *child)
2181d5ac70f0Sopenharmony_ci{
2182d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
2183d5ac70f0Sopenharmony_ci	snd_config_t *parent;
2184d5ac70f0Sopenharmony_ci	assert(after && child);
2185d5ac70f0Sopenharmony_ci	parent = after->parent;
2186d5ac70f0Sopenharmony_ci	assert(parent);
2187d5ac70f0Sopenharmony_ci	if (!child->id || child->parent)
2188d5ac70f0Sopenharmony_ci		return -EINVAL;
2189d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, parent) {
2190d5ac70f0Sopenharmony_ci		snd_config_t *n = snd_config_iterator_entry(i);
2191d5ac70f0Sopenharmony_ci		if (strcmp(child->id, n->id) == 0)
2192d5ac70f0Sopenharmony_ci			return -EEXIST;
2193d5ac70f0Sopenharmony_ci	}
2194d5ac70f0Sopenharmony_ci	child->parent = parent;
2195d5ac70f0Sopenharmony_ci	list_insert(&child->list, &after->list, after->list.next);
2196d5ac70f0Sopenharmony_ci	return 0;
2197d5ac70f0Sopenharmony_ci}
2198d5ac70f0Sopenharmony_ci
2199d5ac70f0Sopenharmony_ci/**
2200d5ac70f0Sopenharmony_ci * \brief Adds a child before another child configuration node.
2201d5ac70f0Sopenharmony_ci * \param before Handle to the start configuration node.
2202d5ac70f0Sopenharmony_ci * \param child Handle to the configuration node to be added.
2203d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2204d5ac70f0Sopenharmony_ci *
2205d5ac70f0Sopenharmony_ci * This function makes the node \a child a child of the parent of
2206d5ac70f0Sopenharmony_ci * the node \a before.
2207d5ac70f0Sopenharmony_ci *
2208d5ac70f0Sopenharmony_ci * The parent node then owns the child node, i.e., the child node gets
2209d5ac70f0Sopenharmony_ci * deleted together with its parent.
2210d5ac70f0Sopenharmony_ci *
2211d5ac70f0Sopenharmony_ci * \a child must have an id.
2212d5ac70f0Sopenharmony_ci *
2213d5ac70f0Sopenharmony_ci * \par Errors:
2214d5ac70f0Sopenharmony_ci * <dl>
2215d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a child does not have an id.
2216d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a child already has a parent.
2217d5ac70f0Sopenharmony_ci * <dt>-EEXIST<dd>\a parent already contains a child node with the same
2218d5ac70f0Sopenharmony_ci *                id as \a child.
2219d5ac70f0Sopenharmony_ci * </dl>
2220d5ac70f0Sopenharmony_ci */
2221d5ac70f0Sopenharmony_ciint snd_config_add_before(snd_config_t *before, snd_config_t *child)
2222d5ac70f0Sopenharmony_ci{
2223d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
2224d5ac70f0Sopenharmony_ci	snd_config_t *parent;
2225d5ac70f0Sopenharmony_ci	assert(before && child);
2226d5ac70f0Sopenharmony_ci	parent = before->parent;
2227d5ac70f0Sopenharmony_ci	assert(parent);
2228d5ac70f0Sopenharmony_ci	if (!child->id || child->parent)
2229d5ac70f0Sopenharmony_ci		return -EINVAL;
2230d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, parent) {
2231d5ac70f0Sopenharmony_ci		snd_config_t *n = snd_config_iterator_entry(i);
2232d5ac70f0Sopenharmony_ci		if (strcmp(child->id, n->id) == 0)
2233d5ac70f0Sopenharmony_ci			return -EEXIST;
2234d5ac70f0Sopenharmony_ci	}
2235d5ac70f0Sopenharmony_ci	child->parent = parent;
2236d5ac70f0Sopenharmony_ci	list_insert(&child->list, before->list.prev, &before->list);
2237d5ac70f0Sopenharmony_ci	return 0;
2238d5ac70f0Sopenharmony_ci}
2239d5ac70f0Sopenharmony_ci
2240d5ac70f0Sopenharmony_ci/*
2241d5ac70f0Sopenharmony_ci * append all src items to the end of dst arrray
2242d5ac70f0Sopenharmony_ci */
2243d5ac70f0Sopenharmony_cistatic int _snd_config_array_merge(snd_config_t *dst, snd_config_t *src, int index)
2244d5ac70f0Sopenharmony_ci{
2245d5ac70f0Sopenharmony_ci	snd_config_iterator_t si, snext;
2246d5ac70f0Sopenharmony_ci	int err;
2247d5ac70f0Sopenharmony_ci
2248d5ac70f0Sopenharmony_ci	snd_config_for_each(si, snext, src) {
2249d5ac70f0Sopenharmony_ci		snd_config_t *sn = snd_config_iterator_entry(si);
2250d5ac70f0Sopenharmony_ci		char id[16];
2251d5ac70f0Sopenharmony_ci		snd_config_remove(sn);
2252d5ac70f0Sopenharmony_ci		snprintf(id, sizeof(id), "%d", index++);
2253d5ac70f0Sopenharmony_ci		err = snd_config_set_id(sn, id);
2254d5ac70f0Sopenharmony_ci		if (err < 0) {
2255d5ac70f0Sopenharmony_ci			snd_config_delete(sn);
2256d5ac70f0Sopenharmony_ci			return err;
2257d5ac70f0Sopenharmony_ci		}
2258d5ac70f0Sopenharmony_ci		sn->parent = dst;
2259d5ac70f0Sopenharmony_ci		list_add_tail(&sn->list, &dst->u.compound.fields);
2260d5ac70f0Sopenharmony_ci	}
2261d5ac70f0Sopenharmony_ci	snd_config_delete(src);
2262d5ac70f0Sopenharmony_ci	return 0;
2263d5ac70f0Sopenharmony_ci}
2264d5ac70f0Sopenharmony_ci
2265d5ac70f0Sopenharmony_ci/**
2266d5ac70f0Sopenharmony_ci * \brief In-place merge of two config handles
2267d5ac70f0Sopenharmony_ci * \param[out] dst Config handle for the merged contents
2268d5ac70f0Sopenharmony_ci * \param[in] src Config handle to merge into dst (may be NULL)
2269d5ac70f0Sopenharmony_ci * \param[in] override Override flag
2270d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2271d5ac70f0Sopenharmony_ci *
2272d5ac70f0Sopenharmony_ci * This function merges all fields from the source compound to the destination compound.
2273d5ac70f0Sopenharmony_ci * When the \a override flag is set, the related subtree in \a dst is replaced from \a src.
2274d5ac70f0Sopenharmony_ci *
2275d5ac70f0Sopenharmony_ci * When \a override is not set, the child compounds are traversed and merged.
2276d5ac70f0Sopenharmony_ci *
2277d5ac70f0Sopenharmony_ci * The configuration elements other than compounds are always substituted (overwritten)
2278d5ac70f0Sopenharmony_ci * from the \a src config handle.
2279d5ac70f0Sopenharmony_ci *
2280d5ac70f0Sopenharmony_ci * The src handle is deleted.
2281d5ac70f0Sopenharmony_ci *
2282d5ac70f0Sopenharmony_ci * Note: On error, config handles may be modified.
2283d5ac70f0Sopenharmony_ci *
2284d5ac70f0Sopenharmony_ci * \par Errors:
2285d5ac70f0Sopenharmony_ci * <dl>
2286d5ac70f0Sopenharmony_ci * <dt>-EEXIST<dd>identifier already exists (!override)
2287d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>not enough memory
2288d5ac70f0Sopenharmony_ci * </dl>
2289d5ac70f0Sopenharmony_ci */
2290d5ac70f0Sopenharmony_ciint snd_config_merge(snd_config_t *dst, snd_config_t *src, int override)
2291d5ac70f0Sopenharmony_ci{
2292d5ac70f0Sopenharmony_ci	snd_config_iterator_t di, si, dnext, snext;
2293d5ac70f0Sopenharmony_ci	bool found;
2294d5ac70f0Sopenharmony_ci	int err, array;
2295d5ac70f0Sopenharmony_ci
2296d5ac70f0Sopenharmony_ci	assert(dst);
2297d5ac70f0Sopenharmony_ci	if (src == NULL)
2298d5ac70f0Sopenharmony_ci		return 0;
2299d5ac70f0Sopenharmony_ci	if (dst->type != SND_CONFIG_TYPE_COMPOUND || src->type != SND_CONFIG_TYPE_COMPOUND)
2300d5ac70f0Sopenharmony_ci		return snd_config_substitute(dst, src);
2301d5ac70f0Sopenharmony_ci	array = snd_config_is_array(dst);
2302d5ac70f0Sopenharmony_ci	if (array && snd_config_is_array(src))
2303d5ac70f0Sopenharmony_ci		return _snd_config_array_merge(dst, src, array);
2304d5ac70f0Sopenharmony_ci	snd_config_for_each(si, snext, src) {
2305d5ac70f0Sopenharmony_ci		snd_config_t *sn = snd_config_iterator_entry(si);
2306d5ac70f0Sopenharmony_ci		found = false;
2307d5ac70f0Sopenharmony_ci		snd_config_for_each(di, dnext, dst) {
2308d5ac70f0Sopenharmony_ci			snd_config_t *dn = snd_config_iterator_entry(di);
2309d5ac70f0Sopenharmony_ci			if (strcmp(sn->id, dn->id) == 0) {
2310d5ac70f0Sopenharmony_ci				if (override ||
2311d5ac70f0Sopenharmony_ci				    sn->type != SND_CONFIG_TYPE_COMPOUND ||
2312d5ac70f0Sopenharmony_ci				    dn->type != SND_CONFIG_TYPE_COMPOUND) {
2313d5ac70f0Sopenharmony_ci					snd_config_remove(sn);
2314d5ac70f0Sopenharmony_ci					err = snd_config_substitute(dn, sn);
2315d5ac70f0Sopenharmony_ci					if (err < 0)
2316d5ac70f0Sopenharmony_ci						return err;
2317d5ac70f0Sopenharmony_ci				} else {
2318d5ac70f0Sopenharmony_ci					err = snd_config_merge(dn, sn, 0);
2319d5ac70f0Sopenharmony_ci					if (err < 0)
2320d5ac70f0Sopenharmony_ci						return err;
2321d5ac70f0Sopenharmony_ci				}
2322d5ac70f0Sopenharmony_ci				found = true;
2323d5ac70f0Sopenharmony_ci				break;
2324d5ac70f0Sopenharmony_ci			}
2325d5ac70f0Sopenharmony_ci		}
2326d5ac70f0Sopenharmony_ci		if (!found) {
2327d5ac70f0Sopenharmony_ci			/* move config from src to dst */
2328d5ac70f0Sopenharmony_ci			snd_config_remove(sn);
2329d5ac70f0Sopenharmony_ci			sn->parent = dst;
2330d5ac70f0Sopenharmony_ci			list_add_tail(&sn->list, &dst->u.compound.fields);
2331d5ac70f0Sopenharmony_ci		}
2332d5ac70f0Sopenharmony_ci	}
2333d5ac70f0Sopenharmony_ci	snd_config_delete(src);
2334d5ac70f0Sopenharmony_ci	return 0;
2335d5ac70f0Sopenharmony_ci}
2336d5ac70f0Sopenharmony_ci
2337d5ac70f0Sopenharmony_ci/**
2338d5ac70f0Sopenharmony_ci * \brief Removes a configuration node from its tree.
2339d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node to be removed.
2340d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2341d5ac70f0Sopenharmony_ci *
2342d5ac70f0Sopenharmony_ci * This function makes \a config a top-level node, i.e., if \a config
2343d5ac70f0Sopenharmony_ci * has a parent, then \a config is removed from the list of the parent's
2344d5ac70f0Sopenharmony_ci * children.
2345d5ac70f0Sopenharmony_ci *
2346d5ac70f0Sopenharmony_ci * This functions does \e not free the removed node.
2347d5ac70f0Sopenharmony_ci *
2348d5ac70f0Sopenharmony_ci * \sa snd_config_delete
2349d5ac70f0Sopenharmony_ci */
2350d5ac70f0Sopenharmony_ciint snd_config_remove(snd_config_t *config)
2351d5ac70f0Sopenharmony_ci{
2352d5ac70f0Sopenharmony_ci	assert(config);
2353d5ac70f0Sopenharmony_ci	if (config->parent)
2354d5ac70f0Sopenharmony_ci		list_del(&config->list);
2355d5ac70f0Sopenharmony_ci	config->parent = NULL;
2356d5ac70f0Sopenharmony_ci	return 0;
2357d5ac70f0Sopenharmony_ci}
2358d5ac70f0Sopenharmony_ci
2359d5ac70f0Sopenharmony_ci/**
2360d5ac70f0Sopenharmony_ci * \brief Frees a configuration node.
2361d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node to be deleted.
2362d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2363d5ac70f0Sopenharmony_ci *
2364d5ac70f0Sopenharmony_ci * This function frees a configuration node and all its resources.
2365d5ac70f0Sopenharmony_ci *
2366d5ac70f0Sopenharmony_ci * If the node is a child node, it is removed from the tree before being
2367d5ac70f0Sopenharmony_ci * deleted.
2368d5ac70f0Sopenharmony_ci *
2369d5ac70f0Sopenharmony_ci * If the node is a compound node, its descendants (the whole subtree)
2370d5ac70f0Sopenharmony_ci * are deleted recursively.
2371d5ac70f0Sopenharmony_ci *
2372d5ac70f0Sopenharmony_ci * The function is supposed to be called only for locally copied config
2373d5ac70f0Sopenharmony_ci * trees.  For the global tree, take the reference via #snd_config_update_ref
2374d5ac70f0Sopenharmony_ci * and free it via #snd_config_unref.
2375d5ac70f0Sopenharmony_ci *
2376d5ac70f0Sopenharmony_ci * \par Conforming to:
2377d5ac70f0Sopenharmony_ci * LSB 3.2
2378d5ac70f0Sopenharmony_ci *
2379d5ac70f0Sopenharmony_ci * \sa snd_config_remove
2380d5ac70f0Sopenharmony_ci */
2381d5ac70f0Sopenharmony_ciint snd_config_delete(snd_config_t *config)
2382d5ac70f0Sopenharmony_ci{
2383d5ac70f0Sopenharmony_ci	assert(config);
2384d5ac70f0Sopenharmony_ci	if (config->refcount > 0) {
2385d5ac70f0Sopenharmony_ci		config->refcount--;
2386d5ac70f0Sopenharmony_ci		return 0;
2387d5ac70f0Sopenharmony_ci	}
2388d5ac70f0Sopenharmony_ci	switch (config->type) {
2389d5ac70f0Sopenharmony_ci	case SND_CONFIG_TYPE_COMPOUND:
2390d5ac70f0Sopenharmony_ci	{
2391d5ac70f0Sopenharmony_ci		int err;
2392d5ac70f0Sopenharmony_ci		struct list_head *i;
2393d5ac70f0Sopenharmony_ci		i = config->u.compound.fields.next;
2394d5ac70f0Sopenharmony_ci		while (i != &config->u.compound.fields) {
2395d5ac70f0Sopenharmony_ci			struct list_head *nexti = i->next;
2396d5ac70f0Sopenharmony_ci			snd_config_t *child = snd_config_iterator_entry(i);
2397d5ac70f0Sopenharmony_ci			err = snd_config_delete(child);
2398d5ac70f0Sopenharmony_ci			if (err < 0)
2399d5ac70f0Sopenharmony_ci				return err;
2400d5ac70f0Sopenharmony_ci			i = nexti;
2401d5ac70f0Sopenharmony_ci		}
2402d5ac70f0Sopenharmony_ci		break;
2403d5ac70f0Sopenharmony_ci	}
2404d5ac70f0Sopenharmony_ci	case SND_CONFIG_TYPE_STRING:
2405d5ac70f0Sopenharmony_ci		free(config->u.string);
2406d5ac70f0Sopenharmony_ci		break;
2407d5ac70f0Sopenharmony_ci	default:
2408d5ac70f0Sopenharmony_ci		break;
2409d5ac70f0Sopenharmony_ci	}
2410d5ac70f0Sopenharmony_ci	if (config->parent)
2411d5ac70f0Sopenharmony_ci		list_del(&config->list);
2412d5ac70f0Sopenharmony_ci	free(config->id);
2413d5ac70f0Sopenharmony_ci	free(config);
2414d5ac70f0Sopenharmony_ci	return 0;
2415d5ac70f0Sopenharmony_ci}
2416d5ac70f0Sopenharmony_ci
2417d5ac70f0Sopenharmony_ci/**
2418d5ac70f0Sopenharmony_ci * \brief Deletes the children of a node.
2419d5ac70f0Sopenharmony_ci * \param config Handle to the compound configuration node.
2420d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2421d5ac70f0Sopenharmony_ci *
2422d5ac70f0Sopenharmony_ci * This function removes and frees all children of a configuration node.
2423d5ac70f0Sopenharmony_ci *
2424d5ac70f0Sopenharmony_ci * Any compound nodes among the children of \a config are deleted
2425d5ac70f0Sopenharmony_ci * recursively.
2426d5ac70f0Sopenharmony_ci *
2427d5ac70f0Sopenharmony_ci * After a successful call to this function, \a config is an empty
2428d5ac70f0Sopenharmony_ci * compound node.
2429d5ac70f0Sopenharmony_ci *
2430d5ac70f0Sopenharmony_ci * \par Errors:
2431d5ac70f0Sopenharmony_ci * <dl>
2432d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not a compound node.
2433d5ac70f0Sopenharmony_ci * </dl>
2434d5ac70f0Sopenharmony_ci */
2435d5ac70f0Sopenharmony_ciint snd_config_delete_compound_members(const snd_config_t *config)
2436d5ac70f0Sopenharmony_ci{
2437d5ac70f0Sopenharmony_ci	int err;
2438d5ac70f0Sopenharmony_ci	struct list_head *i;
2439d5ac70f0Sopenharmony_ci
2440d5ac70f0Sopenharmony_ci	assert(config);
2441d5ac70f0Sopenharmony_ci	if (config->type != SND_CONFIG_TYPE_COMPOUND)
2442d5ac70f0Sopenharmony_ci		return -EINVAL;
2443d5ac70f0Sopenharmony_ci	i = config->u.compound.fields.next;
2444d5ac70f0Sopenharmony_ci	while (i != &config->u.compound.fields) {
2445d5ac70f0Sopenharmony_ci		struct list_head *nexti = i->next;
2446d5ac70f0Sopenharmony_ci		snd_config_t *child = snd_config_iterator_entry(i);
2447d5ac70f0Sopenharmony_ci		err = snd_config_delete(child);
2448d5ac70f0Sopenharmony_ci		if (err < 0)
2449d5ac70f0Sopenharmony_ci			return err;
2450d5ac70f0Sopenharmony_ci		i = nexti;
2451d5ac70f0Sopenharmony_ci	}
2452d5ac70f0Sopenharmony_ci	return 0;
2453d5ac70f0Sopenharmony_ci}
2454d5ac70f0Sopenharmony_ci
2455d5ac70f0Sopenharmony_ci/**
2456d5ac70f0Sopenharmony_ci * \brief Creates a configuration node.
2457d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at
2458d5ac70f0Sopenharmony_ci *                    the address specified by \a config.
2459d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node.
2460d5ac70f0Sopenharmony_ci * \param[in] type The type of the new node.
2461d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2462d5ac70f0Sopenharmony_ci *
2463d5ac70f0Sopenharmony_ci * This functions creates a new node of the specified type.
2464d5ac70f0Sopenharmony_ci * The new node has id \a id, which may be \c NULL.
2465d5ac70f0Sopenharmony_ci *
2466d5ac70f0Sopenharmony_ci * The value of the new node is zero (for numbers), or \c NULL (for
2467d5ac70f0Sopenharmony_ci * strings and pointers), or empty (for compound nodes).
2468d5ac70f0Sopenharmony_ci *
2469d5ac70f0Sopenharmony_ci * \par Errors:
2470d5ac70f0Sopenharmony_ci * <dl>
2471d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory.
2472d5ac70f0Sopenharmony_ci * </dl>
2473d5ac70f0Sopenharmony_ci */
2474d5ac70f0Sopenharmony_ciint snd_config_make(snd_config_t **config, const char *id,
2475d5ac70f0Sopenharmony_ci		    snd_config_type_t type)
2476d5ac70f0Sopenharmony_ci{
2477d5ac70f0Sopenharmony_ci	char *id1;
2478d5ac70f0Sopenharmony_ci	assert(config);
2479d5ac70f0Sopenharmony_ci	if (id) {
2480d5ac70f0Sopenharmony_ci		id1 = strdup(id);
2481d5ac70f0Sopenharmony_ci		if (!id1)
2482d5ac70f0Sopenharmony_ci			return -ENOMEM;
2483d5ac70f0Sopenharmony_ci	} else
2484d5ac70f0Sopenharmony_ci		id1 = NULL;
2485d5ac70f0Sopenharmony_ci	return _snd_config_make(config, &id1, type);
2486d5ac70f0Sopenharmony_ci}
2487d5ac70f0Sopenharmony_ci
2488d5ac70f0Sopenharmony_ci/**
2489d5ac70f0Sopenharmony_ci * \brief Creates an integer configuration node.
2490d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at
2491d5ac70f0Sopenharmony_ci *                    the address specified by \a config.
2492d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node.
2493d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2494d5ac70f0Sopenharmony_ci *
2495d5ac70f0Sopenharmony_ci * This function creates a new node of type #SND_CONFIG_TYPE_INTEGER and
2496d5ac70f0Sopenharmony_ci * with value \c 0.
2497d5ac70f0Sopenharmony_ci *
2498d5ac70f0Sopenharmony_ci * \par Errors:
2499d5ac70f0Sopenharmony_ci * <dl>
2500d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory.
2501d5ac70f0Sopenharmony_ci * </dl>
2502d5ac70f0Sopenharmony_ci *
2503d5ac70f0Sopenharmony_ci * \par Conforming to:
2504d5ac70f0Sopenharmony_ci * LSB 3.2
2505d5ac70f0Sopenharmony_ci *
2506d5ac70f0Sopenharmony_ci * \sa snd_config_imake_integer
2507d5ac70f0Sopenharmony_ci */
2508d5ac70f0Sopenharmony_ciint snd_config_make_integer(snd_config_t **config, const char *id)
2509d5ac70f0Sopenharmony_ci{
2510d5ac70f0Sopenharmony_ci	return snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER);
2511d5ac70f0Sopenharmony_ci}
2512d5ac70f0Sopenharmony_ci
2513d5ac70f0Sopenharmony_ci/**
2514d5ac70f0Sopenharmony_ci * \brief Creates a 64-bit-integer configuration node.
2515d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at
2516d5ac70f0Sopenharmony_ci *                    the address specified by \a config.
2517d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node.
2518d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2519d5ac70f0Sopenharmony_ci *
2520d5ac70f0Sopenharmony_ci * This function creates a new node of type #SND_CONFIG_TYPE_INTEGER64
2521d5ac70f0Sopenharmony_ci * and with value \c 0.
2522d5ac70f0Sopenharmony_ci *
2523d5ac70f0Sopenharmony_ci * \par Errors:
2524d5ac70f0Sopenharmony_ci * <dl>
2525d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory.
2526d5ac70f0Sopenharmony_ci * </dl>
2527d5ac70f0Sopenharmony_ci *
2528d5ac70f0Sopenharmony_ci * \par Conforming to:
2529d5ac70f0Sopenharmony_ci * LSB 3.2
2530d5ac70f0Sopenharmony_ci *
2531d5ac70f0Sopenharmony_ci * \sa snd_config_imake_integer64
2532d5ac70f0Sopenharmony_ci */
2533d5ac70f0Sopenharmony_ciint snd_config_make_integer64(snd_config_t **config, const char *id)
2534d5ac70f0Sopenharmony_ci{
2535d5ac70f0Sopenharmony_ci	return snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER64);
2536d5ac70f0Sopenharmony_ci}
2537d5ac70f0Sopenharmony_ci
2538d5ac70f0Sopenharmony_ci/**
2539d5ac70f0Sopenharmony_ci * \brief Creates a real number configuration node.
2540d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at
2541d5ac70f0Sopenharmony_ci *                    the address specified by \a config.
2542d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node.
2543d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2544d5ac70f0Sopenharmony_ci *
2545d5ac70f0Sopenharmony_ci * This function creates a new node of type #SND_CONFIG_TYPE_REAL and
2546d5ac70f0Sopenharmony_ci * with value \c 0.0.
2547d5ac70f0Sopenharmony_ci *
2548d5ac70f0Sopenharmony_ci * \par Errors:
2549d5ac70f0Sopenharmony_ci * <dl>
2550d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory.
2551d5ac70f0Sopenharmony_ci * </dl>
2552d5ac70f0Sopenharmony_ci *
2553d5ac70f0Sopenharmony_ci * \sa snd_config_imake_real
2554d5ac70f0Sopenharmony_ci */
2555d5ac70f0Sopenharmony_ciint snd_config_make_real(snd_config_t **config, const char *id)
2556d5ac70f0Sopenharmony_ci{
2557d5ac70f0Sopenharmony_ci	return snd_config_make(config, id, SND_CONFIG_TYPE_REAL);
2558d5ac70f0Sopenharmony_ci}
2559d5ac70f0Sopenharmony_ci
2560d5ac70f0Sopenharmony_ci/**
2561d5ac70f0Sopenharmony_ci * \brief Creates a string configuration node.
2562d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at
2563d5ac70f0Sopenharmony_ci *                    the address specified by \a config.
2564d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node.
2565d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2566d5ac70f0Sopenharmony_ci *
2567d5ac70f0Sopenharmony_ci * This function creates a new node of type #SND_CONFIG_TYPE_STRING and
2568d5ac70f0Sopenharmony_ci * with value \c NULL.
2569d5ac70f0Sopenharmony_ci *
2570d5ac70f0Sopenharmony_ci * \par Errors:
2571d5ac70f0Sopenharmony_ci * <dl>
2572d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory.
2573d5ac70f0Sopenharmony_ci * </dl>
2574d5ac70f0Sopenharmony_ci *
2575d5ac70f0Sopenharmony_ci * \par Conforming to:
2576d5ac70f0Sopenharmony_ci * LSB 3.2
2577d5ac70f0Sopenharmony_ci *
2578d5ac70f0Sopenharmony_ci * \sa snd_config_imake_string
2579d5ac70f0Sopenharmony_ci */
2580d5ac70f0Sopenharmony_ciint snd_config_make_string(snd_config_t **config, const char *id)
2581d5ac70f0Sopenharmony_ci{
2582d5ac70f0Sopenharmony_ci	return snd_config_make(config, id, SND_CONFIG_TYPE_STRING);
2583d5ac70f0Sopenharmony_ci}
2584d5ac70f0Sopenharmony_ci
2585d5ac70f0Sopenharmony_ci/**
2586d5ac70f0Sopenharmony_ci * \brief Creates a pointer configuration node.
2587d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at
2588d5ac70f0Sopenharmony_ci *                    the address specified by \a config.
2589d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node.
2590d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2591d5ac70f0Sopenharmony_ci *
2592d5ac70f0Sopenharmony_ci * This function creates a new node of type #SND_CONFIG_TYPE_POINTER and
2593d5ac70f0Sopenharmony_ci * with value \c NULL.
2594d5ac70f0Sopenharmony_ci *
2595d5ac70f0Sopenharmony_ci * \par Errors:
2596d5ac70f0Sopenharmony_ci * <dl>
2597d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory.
2598d5ac70f0Sopenharmony_ci * </dl>
2599d5ac70f0Sopenharmony_ci *
2600d5ac70f0Sopenharmony_ci * \sa snd_config_imake_pointer
2601d5ac70f0Sopenharmony_ci */
2602d5ac70f0Sopenharmony_ciint snd_config_make_pointer(snd_config_t **config, const char *id)
2603d5ac70f0Sopenharmony_ci{
2604d5ac70f0Sopenharmony_ci	return snd_config_make(config, id, SND_CONFIG_TYPE_POINTER);
2605d5ac70f0Sopenharmony_ci}
2606d5ac70f0Sopenharmony_ci
2607d5ac70f0Sopenharmony_ci/**
2608d5ac70f0Sopenharmony_ci * \brief Creates an empty compound configuration node.
2609d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at
2610d5ac70f0Sopenharmony_ci *                    the address specified by \a config.
2611d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node.
2612d5ac70f0Sopenharmony_ci * \param[in] join Join flag.
2613d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2614d5ac70f0Sopenharmony_ci *
2615d5ac70f0Sopenharmony_ci * This function creates a new empty node of type
2616d5ac70f0Sopenharmony_ci * #SND_CONFIG_TYPE_COMPOUND.
2617d5ac70f0Sopenharmony_ci *
2618d5ac70f0Sopenharmony_ci * \a join determines how the compound node's id is printed when the
2619d5ac70f0Sopenharmony_ci * configuration is saved to a text file.  For example, if the join flag
2620d5ac70f0Sopenharmony_ci * of compound node \c a is zero, the output will look as follows:
2621d5ac70f0Sopenharmony_ci * \code
2622d5ac70f0Sopenharmony_ci * a {
2623d5ac70f0Sopenharmony_ci *     b "hello"
2624d5ac70f0Sopenharmony_ci *     c 42
2625d5ac70f0Sopenharmony_ci * }
2626d5ac70f0Sopenharmony_ci * \endcode
2627d5ac70f0Sopenharmony_ci * If, however, the join flag of \c a is nonzero, its id will be joined
2628d5ac70f0Sopenharmony_ci * with its children's ids, like this:
2629d5ac70f0Sopenharmony_ci * \code
2630d5ac70f0Sopenharmony_ci * a.b "hello"
2631d5ac70f0Sopenharmony_ci * a.c 42
2632d5ac70f0Sopenharmony_ci * \endcode
2633d5ac70f0Sopenharmony_ci * An \e empty compound node with its join flag set would result in no
2634d5ac70f0Sopenharmony_ci * output, i.e., after saving and reloading the configuration file, that
2635d5ac70f0Sopenharmony_ci * compound node would be lost.
2636d5ac70f0Sopenharmony_ci *
2637d5ac70f0Sopenharmony_ci * \par Errors:
2638d5ac70f0Sopenharmony_ci * <dl>
2639d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory.
2640d5ac70f0Sopenharmony_ci * </dl>
2641d5ac70f0Sopenharmony_ci *
2642d5ac70f0Sopenharmony_ci * \par Conforming to:
2643d5ac70f0Sopenharmony_ci * LSB 3.2
2644d5ac70f0Sopenharmony_ci */
2645d5ac70f0Sopenharmony_ciint snd_config_make_compound(snd_config_t **config, const char *id,
2646d5ac70f0Sopenharmony_ci			     int join)
2647d5ac70f0Sopenharmony_ci{
2648d5ac70f0Sopenharmony_ci	int err;
2649d5ac70f0Sopenharmony_ci	err = snd_config_make(config, id, SND_CONFIG_TYPE_COMPOUND);
2650d5ac70f0Sopenharmony_ci	if (err < 0)
2651d5ac70f0Sopenharmony_ci		return err;
2652d5ac70f0Sopenharmony_ci	(*config)->u.compound.join = join;
2653d5ac70f0Sopenharmony_ci	return 0;
2654d5ac70f0Sopenharmony_ci}
2655d5ac70f0Sopenharmony_ci
2656d5ac70f0Sopenharmony_ci/**
2657d5ac70f0Sopenharmony_ci * \brief Creates an empty compound configuration node in the path.
2658d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new or
2659d5ac70f0Sopenharmony_ci *		      existing compound node at the address specified
2660d5ac70f0Sopenharmony_ci *		      by \a config.
2661d5ac70f0Sopenharmony_ci * \param[in] root The id of the new node.
2662d5ac70f0Sopenharmony_ci * \param[in] key The id of the new node.
2663d5ac70f0Sopenharmony_ci * \param[in] join Join flag.
2664d5ac70f0Sopenharmony_ci * \param[in] override Override flag.
2665d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2666d5ac70f0Sopenharmony_ci *
2667d5ac70f0Sopenharmony_ci * This function creates a new empty node of type
2668d5ac70f0Sopenharmony_ci * #SND_CONFIG_TYPE_COMPOUND if the path does not exist. Otherwise,
2669d5ac70f0Sopenharmony_ci * the node from the current configuration tree is returned without
2670d5ac70f0Sopenharmony_ci * any modification. The \a join argument is ignored in this case.
2671d5ac70f0Sopenharmony_ci *
2672d5ac70f0Sopenharmony_ci * \a join determines how the compound node's id is printed when the
2673d5ac70f0Sopenharmony_ci * configuration is saved to a text file.  For example, if the join flag
2674d5ac70f0Sopenharmony_ci * of compound node \c a is zero, the output will look as follows:
2675d5ac70f0Sopenharmony_ci * \code
2676d5ac70f0Sopenharmony_ci * a {
2677d5ac70f0Sopenharmony_ci *     b "hello"
2678d5ac70f0Sopenharmony_ci *     c 42
2679d5ac70f0Sopenharmony_ci * }
2680d5ac70f0Sopenharmony_ci * \endcode
2681d5ac70f0Sopenharmony_ci * If, however, the join flag of \c a is nonzero, its id will be joined
2682d5ac70f0Sopenharmony_ci * with its children's ids, like this:
2683d5ac70f0Sopenharmony_ci * \code
2684d5ac70f0Sopenharmony_ci * a.b "hello"
2685d5ac70f0Sopenharmony_ci * a.c 42
2686d5ac70f0Sopenharmony_ci * \endcode
2687d5ac70f0Sopenharmony_ci * An \e empty compound node with its join flag set would result in no
2688d5ac70f0Sopenharmony_ci * output, i.e., after saving and reloading the configuration file, that
2689d5ac70f0Sopenharmony_ci * compound node would be lost.
2690d5ac70f0Sopenharmony_ci *
2691d5ac70f0Sopenharmony_ci * \par Errors:
2692d5ac70f0Sopenharmony_ci * <dl>
2693d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory.
2694d5ac70f0Sopenharmony_ci * <dt>-EACCESS<dd>Path exists, but it's not a compound (!override)
2695d5ac70f0Sopenharmony_ci * </dl>
2696d5ac70f0Sopenharmony_ci */
2697d5ac70f0Sopenharmony_ciint snd_config_make_path(snd_config_t **config, snd_config_t *root,
2698d5ac70f0Sopenharmony_ci			 const char *key, int join, int override)
2699d5ac70f0Sopenharmony_ci{
2700d5ac70f0Sopenharmony_ci	snd_config_t *n;
2701d5ac70f0Sopenharmony_ci	const char *p;
2702d5ac70f0Sopenharmony_ci	int err;
2703d5ac70f0Sopenharmony_ci
2704d5ac70f0Sopenharmony_ci	while (1) {
2705d5ac70f0Sopenharmony_ci		p = strchr(key, '.');
2706d5ac70f0Sopenharmony_ci		if (p) {
2707d5ac70f0Sopenharmony_ci			err = _snd_config_search(root, key, p - key, &n);
2708d5ac70f0Sopenharmony_ci			if (err < 0) {
2709d5ac70f0Sopenharmony_ci				size_t l = p - key;
2710d5ac70f0Sopenharmony_ci				char *s = malloc(l + 1);
2711d5ac70f0Sopenharmony_ci				if (s == NULL)
2712d5ac70f0Sopenharmony_ci					return -ENOMEM;
2713d5ac70f0Sopenharmony_ci				strncpy(s, key, l);
2714d5ac70f0Sopenharmony_ci				s[l] = '\0';
2715d5ac70f0Sopenharmony_ci				err = snd_config_make_compound(&n, s, join);
2716d5ac70f0Sopenharmony_ci				free(s);
2717d5ac70f0Sopenharmony_ci				if (err < 0)
2718d5ac70f0Sopenharmony_ci					return err;
2719d5ac70f0Sopenharmony_ci				err = snd_config_add(root, n);
2720d5ac70f0Sopenharmony_ci				if (err < 0)
2721d5ac70f0Sopenharmony_ci					return err;
2722d5ac70f0Sopenharmony_ci			}
2723d5ac70f0Sopenharmony_ci			root = n;
2724d5ac70f0Sopenharmony_ci			key = p + 1;
2725d5ac70f0Sopenharmony_ci		} else {
2726d5ac70f0Sopenharmony_ci			err = _snd_config_search(root, key, -1, config);
2727d5ac70f0Sopenharmony_ci			if (err == 0) {
2728d5ac70f0Sopenharmony_ci				if ((*config)->type != SND_CONFIG_TYPE_COMPOUND) {
2729d5ac70f0Sopenharmony_ci					if (override) {
2730d5ac70f0Sopenharmony_ci						err = snd_config_delete(*config);
2731d5ac70f0Sopenharmony_ci						if (err < 0)
2732d5ac70f0Sopenharmony_ci							return err;
2733d5ac70f0Sopenharmony_ci						goto __make;
2734d5ac70f0Sopenharmony_ci					} else {
2735d5ac70f0Sopenharmony_ci						return -EACCES;
2736d5ac70f0Sopenharmony_ci					}
2737d5ac70f0Sopenharmony_ci				}
2738d5ac70f0Sopenharmony_ci				return 0;
2739d5ac70f0Sopenharmony_ci			}
2740d5ac70f0Sopenharmony_ci__make:
2741d5ac70f0Sopenharmony_ci			err = snd_config_make_compound(&n, key, join);
2742d5ac70f0Sopenharmony_ci			if (err < 0)
2743d5ac70f0Sopenharmony_ci				return err;
2744d5ac70f0Sopenharmony_ci			err = snd_config_add(root, n);
2745d5ac70f0Sopenharmony_ci			if (err < 0)
2746d5ac70f0Sopenharmony_ci				return err;
2747d5ac70f0Sopenharmony_ci			*config = n;
2748d5ac70f0Sopenharmony_ci			return 0;
2749d5ac70f0Sopenharmony_ci		}
2750d5ac70f0Sopenharmony_ci	}
2751d5ac70f0Sopenharmony_ci}
2752d5ac70f0Sopenharmony_ci
2753d5ac70f0Sopenharmony_ci/**
2754d5ac70f0Sopenharmony_ci * \brief Creates an integer configuration node with the given initial value.
2755d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at
2756d5ac70f0Sopenharmony_ci *                    the address specified by \a config.
2757d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node.
2758d5ac70f0Sopenharmony_ci * \param[in] value The initial value of the new node.
2759d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2760d5ac70f0Sopenharmony_ci *
2761d5ac70f0Sopenharmony_ci * This function creates a new node of type #SND_CONFIG_TYPE_INTEGER and
2762d5ac70f0Sopenharmony_ci * with value \a value.
2763d5ac70f0Sopenharmony_ci *
2764d5ac70f0Sopenharmony_ci * \par Errors:
2765d5ac70f0Sopenharmony_ci * <dl>
2766d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory.
2767d5ac70f0Sopenharmony_ci * </dl>
2768d5ac70f0Sopenharmony_ci *
2769d5ac70f0Sopenharmony_ci * \par Conforming to:
2770d5ac70f0Sopenharmony_ci * LSB 3.2
2771d5ac70f0Sopenharmony_ci */
2772d5ac70f0Sopenharmony_ciint snd_config_imake_integer(snd_config_t **config, const char *id, const long value)
2773d5ac70f0Sopenharmony_ci{
2774d5ac70f0Sopenharmony_ci	int err;
2775d5ac70f0Sopenharmony_ci
2776d5ac70f0Sopenharmony_ci	err = snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER);
2777d5ac70f0Sopenharmony_ci	if (err < 0)
2778d5ac70f0Sopenharmony_ci		return err;
2779d5ac70f0Sopenharmony_ci	(*config)->u.integer = value;
2780d5ac70f0Sopenharmony_ci	return 0;
2781d5ac70f0Sopenharmony_ci}
2782d5ac70f0Sopenharmony_ci
2783d5ac70f0Sopenharmony_ci/**
2784d5ac70f0Sopenharmony_ci * \brief Creates a 64-bit-integer configuration node with the given initial value.
2785d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at
2786d5ac70f0Sopenharmony_ci *                    the address specified by \a config.
2787d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node.
2788d5ac70f0Sopenharmony_ci * \param[in] value The initial value of the new node.
2789d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2790d5ac70f0Sopenharmony_ci *
2791d5ac70f0Sopenharmony_ci * This function creates a new node of type #SND_CONFIG_TYPE_INTEGER64
2792d5ac70f0Sopenharmony_ci * and with value \a value.
2793d5ac70f0Sopenharmony_ci *
2794d5ac70f0Sopenharmony_ci * \par Errors:
2795d5ac70f0Sopenharmony_ci * <dl>
2796d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory.
2797d5ac70f0Sopenharmony_ci * </dl>
2798d5ac70f0Sopenharmony_ci *
2799d5ac70f0Sopenharmony_ci * \par Conforming to:
2800d5ac70f0Sopenharmony_ci * LSB 3.2
2801d5ac70f0Sopenharmony_ci */
2802d5ac70f0Sopenharmony_ciint snd_config_imake_integer64(snd_config_t **config, const char *id, const long long value)
2803d5ac70f0Sopenharmony_ci{
2804d5ac70f0Sopenharmony_ci	int err;
2805d5ac70f0Sopenharmony_ci
2806d5ac70f0Sopenharmony_ci	err = snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER64);
2807d5ac70f0Sopenharmony_ci	if (err < 0)
2808d5ac70f0Sopenharmony_ci		return err;
2809d5ac70f0Sopenharmony_ci	(*config)->u.integer64 = value;
2810d5ac70f0Sopenharmony_ci	return 0;
2811d5ac70f0Sopenharmony_ci}
2812d5ac70f0Sopenharmony_ci
2813d5ac70f0Sopenharmony_ci/**
2814d5ac70f0Sopenharmony_ci * \brief Creates a real number configuration node with the given initial value.
2815d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at
2816d5ac70f0Sopenharmony_ci *                    the address specified by \a config.
2817d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node.
2818d5ac70f0Sopenharmony_ci * \param[in] value The initial value of the new node.
2819d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2820d5ac70f0Sopenharmony_ci *
2821d5ac70f0Sopenharmony_ci * This function creates a new node of type #SND_CONFIG_TYPE_REAL and
2822d5ac70f0Sopenharmony_ci * with value \a value.
2823d5ac70f0Sopenharmony_ci *
2824d5ac70f0Sopenharmony_ci * \par Errors:
2825d5ac70f0Sopenharmony_ci * <dl>
2826d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory.
2827d5ac70f0Sopenharmony_ci * </dl>
2828d5ac70f0Sopenharmony_ci */
2829d5ac70f0Sopenharmony_ciint snd_config_imake_real(snd_config_t **config, const char *id, const double value)
2830d5ac70f0Sopenharmony_ci{
2831d5ac70f0Sopenharmony_ci	int err;
2832d5ac70f0Sopenharmony_ci
2833d5ac70f0Sopenharmony_ci	err = snd_config_make(config, id, SND_CONFIG_TYPE_REAL);
2834d5ac70f0Sopenharmony_ci	if (err < 0)
2835d5ac70f0Sopenharmony_ci		return err;
2836d5ac70f0Sopenharmony_ci	(*config)->u.real = value;
2837d5ac70f0Sopenharmony_ci	return 0;
2838d5ac70f0Sopenharmony_ci}
2839d5ac70f0Sopenharmony_ci
2840d5ac70f0Sopenharmony_ci/**
2841d5ac70f0Sopenharmony_ci * \brief Creates a string configuration node with the given initial value.
2842d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at
2843d5ac70f0Sopenharmony_ci *                    the address specified by \a config.
2844d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node.
2845d5ac70f0Sopenharmony_ci * \param[in] value The initial value of the new node.  May be \c NULL.
2846d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2847d5ac70f0Sopenharmony_ci *
2848d5ac70f0Sopenharmony_ci * This function creates a new node of type #SND_CONFIG_TYPE_STRING and
2849d5ac70f0Sopenharmony_ci * with a copy of the string \c value.
2850d5ac70f0Sopenharmony_ci *
2851d5ac70f0Sopenharmony_ci * \par Errors:
2852d5ac70f0Sopenharmony_ci * <dl>
2853d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory.
2854d5ac70f0Sopenharmony_ci * </dl>
2855d5ac70f0Sopenharmony_ci *
2856d5ac70f0Sopenharmony_ci * \par Conforming to:
2857d5ac70f0Sopenharmony_ci * LSB 3.2
2858d5ac70f0Sopenharmony_ci */
2859d5ac70f0Sopenharmony_ciint snd_config_imake_string(snd_config_t **config, const char *id, const char *value)
2860d5ac70f0Sopenharmony_ci{
2861d5ac70f0Sopenharmony_ci	int err;
2862d5ac70f0Sopenharmony_ci	snd_config_t *tmp;
2863d5ac70f0Sopenharmony_ci
2864d5ac70f0Sopenharmony_ci	err = snd_config_make(&tmp, id, SND_CONFIG_TYPE_STRING);
2865d5ac70f0Sopenharmony_ci	if (err < 0)
2866d5ac70f0Sopenharmony_ci		return err;
2867d5ac70f0Sopenharmony_ci	if (value) {
2868d5ac70f0Sopenharmony_ci		tmp->u.string = strdup(value);
2869d5ac70f0Sopenharmony_ci		if (!tmp->u.string) {
2870d5ac70f0Sopenharmony_ci			snd_config_delete(tmp);
2871d5ac70f0Sopenharmony_ci			return -ENOMEM;
2872d5ac70f0Sopenharmony_ci		}
2873d5ac70f0Sopenharmony_ci	} else {
2874d5ac70f0Sopenharmony_ci		tmp->u.string = NULL;
2875d5ac70f0Sopenharmony_ci	}
2876d5ac70f0Sopenharmony_ci	*config = tmp;
2877d5ac70f0Sopenharmony_ci	return 0;
2878d5ac70f0Sopenharmony_ci}
2879d5ac70f0Sopenharmony_ci
2880d5ac70f0Sopenharmony_ci/**
2881d5ac70f0Sopenharmony_ci * \brief Creates a string configuration node with the given initial value.
2882d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at
2883d5ac70f0Sopenharmony_ci *                    the address specified by \a config.
2884d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node.
2885d5ac70f0Sopenharmony_ci * \param[in] value The initial value of the new node.  May be \c NULL.
2886d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2887d5ac70f0Sopenharmony_ci *
2888d5ac70f0Sopenharmony_ci * This function creates a new node of type #SND_CONFIG_TYPE_STRING. The node
2889d5ac70f0Sopenharmony_ci * contains with a copy of the string \c value, replacing any character other
2890d5ac70f0Sopenharmony_ci * than alphanumeric, space, or '-' with the character '_'.
2891d5ac70f0Sopenharmony_ci *
2892d5ac70f0Sopenharmony_ci * \par Errors:
2893d5ac70f0Sopenharmony_ci * <dl>
2894d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory.
2895d5ac70f0Sopenharmony_ci * </dl>
2896d5ac70f0Sopenharmony_ci *
2897d5ac70f0Sopenharmony_ci * \par Conforming to:
2898d5ac70f0Sopenharmony_ci * LSB 3.2
2899d5ac70f0Sopenharmony_ci */
2900d5ac70f0Sopenharmony_ciint snd_config_imake_safe_string(snd_config_t **config, const char *id, const char *value)
2901d5ac70f0Sopenharmony_ci{
2902d5ac70f0Sopenharmony_ci	int err;
2903d5ac70f0Sopenharmony_ci	snd_config_t *tmp;
2904d5ac70f0Sopenharmony_ci	char *c;
2905d5ac70f0Sopenharmony_ci
2906d5ac70f0Sopenharmony_ci	err = snd_config_make(&tmp, id, SND_CONFIG_TYPE_STRING);
2907d5ac70f0Sopenharmony_ci	if (err < 0)
2908d5ac70f0Sopenharmony_ci		return err;
2909d5ac70f0Sopenharmony_ci	if (value) {
2910d5ac70f0Sopenharmony_ci		tmp->u.string = strdup(value);
2911d5ac70f0Sopenharmony_ci		if (!tmp->u.string) {
2912d5ac70f0Sopenharmony_ci			snd_config_delete(tmp);
2913d5ac70f0Sopenharmony_ci			return -ENOMEM;
2914d5ac70f0Sopenharmony_ci		}
2915d5ac70f0Sopenharmony_ci
2916d5ac70f0Sopenharmony_ci		for (c = tmp->u.string; *c; c++) {
2917d5ac70f0Sopenharmony_ci			if (*c == ' ' || *c == '-' || *c == '_' ||
2918d5ac70f0Sopenharmony_ci				(*c >= '0' && *c <= '9') ||
2919d5ac70f0Sopenharmony_ci				(*c >= 'a' && *c <= 'z') ||
2920d5ac70f0Sopenharmony_ci				(*c >= 'A' && *c <= 'Z'))
2921d5ac70f0Sopenharmony_ci					continue;
2922d5ac70f0Sopenharmony_ci			*c = '_';
2923d5ac70f0Sopenharmony_ci		}
2924d5ac70f0Sopenharmony_ci	} else {
2925d5ac70f0Sopenharmony_ci		tmp->u.string = NULL;
2926d5ac70f0Sopenharmony_ci	}
2927d5ac70f0Sopenharmony_ci	*config = tmp;
2928d5ac70f0Sopenharmony_ci	return 0;
2929d5ac70f0Sopenharmony_ci}
2930d5ac70f0Sopenharmony_ci
2931d5ac70f0Sopenharmony_ci
2932d5ac70f0Sopenharmony_ci/**
2933d5ac70f0Sopenharmony_ci * \brief Creates a pointer configuration node with the given initial value.
2934d5ac70f0Sopenharmony_ci * \param[out] config The function puts the handle to the new node at
2935d5ac70f0Sopenharmony_ci *                    the address specified by \a config.
2936d5ac70f0Sopenharmony_ci * \param[in] id The id of the new node.
2937d5ac70f0Sopenharmony_ci * \param[in] value The initial value of the new node.
2938d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2939d5ac70f0Sopenharmony_ci *
2940d5ac70f0Sopenharmony_ci * This function creates a new node of type #SND_CONFIG_TYPE_POINTER and
2941d5ac70f0Sopenharmony_ci * with value \c value.
2942d5ac70f0Sopenharmony_ci *
2943d5ac70f0Sopenharmony_ci * \par Errors:
2944d5ac70f0Sopenharmony_ci * <dl>
2945d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory.
2946d5ac70f0Sopenharmony_ci * </dl>
2947d5ac70f0Sopenharmony_ci */
2948d5ac70f0Sopenharmony_ciint snd_config_imake_pointer(snd_config_t **config, const char *id, const void *value)
2949d5ac70f0Sopenharmony_ci{
2950d5ac70f0Sopenharmony_ci	int err;
2951d5ac70f0Sopenharmony_ci
2952d5ac70f0Sopenharmony_ci	err = snd_config_make(config, id, SND_CONFIG_TYPE_POINTER);
2953d5ac70f0Sopenharmony_ci	if (err < 0)
2954d5ac70f0Sopenharmony_ci		return err;
2955d5ac70f0Sopenharmony_ci	(*config)->u.ptr = value;
2956d5ac70f0Sopenharmony_ci	return 0;
2957d5ac70f0Sopenharmony_ci}
2958d5ac70f0Sopenharmony_ci
2959d5ac70f0Sopenharmony_ci/**
2960d5ac70f0Sopenharmony_ci * \brief Changes the value of an integer configuration node.
2961d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node.
2962d5ac70f0Sopenharmony_ci * \param value The new value for the node.
2963d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2964d5ac70f0Sopenharmony_ci *
2965d5ac70f0Sopenharmony_ci * \par Errors:
2966d5ac70f0Sopenharmony_ci * <dl>
2967d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not an integer node.
2968d5ac70f0Sopenharmony_ci * </dl>
2969d5ac70f0Sopenharmony_ci *
2970d5ac70f0Sopenharmony_ci * \par Conforming to:
2971d5ac70f0Sopenharmony_ci * LSB 3.2
2972d5ac70f0Sopenharmony_ci */
2973d5ac70f0Sopenharmony_ciint snd_config_set_integer(snd_config_t *config, long value)
2974d5ac70f0Sopenharmony_ci{
2975d5ac70f0Sopenharmony_ci	assert(config);
2976d5ac70f0Sopenharmony_ci	if (config->type != SND_CONFIG_TYPE_INTEGER)
2977d5ac70f0Sopenharmony_ci		return -EINVAL;
2978d5ac70f0Sopenharmony_ci	config->u.integer = value;
2979d5ac70f0Sopenharmony_ci	return 0;
2980d5ac70f0Sopenharmony_ci}
2981d5ac70f0Sopenharmony_ci
2982d5ac70f0Sopenharmony_ci/**
2983d5ac70f0Sopenharmony_ci * \brief Changes the value of a 64-bit-integer configuration node.
2984d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node.
2985d5ac70f0Sopenharmony_ci * \param value The new value for the node.
2986d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
2987d5ac70f0Sopenharmony_ci *
2988d5ac70f0Sopenharmony_ci * \par Errors:
2989d5ac70f0Sopenharmony_ci * <dl>
2990d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not a 64-bit-integer node.
2991d5ac70f0Sopenharmony_ci * </dl>
2992d5ac70f0Sopenharmony_ci *
2993d5ac70f0Sopenharmony_ci * \par Conforming to:
2994d5ac70f0Sopenharmony_ci * LSB 3.2
2995d5ac70f0Sopenharmony_ci */
2996d5ac70f0Sopenharmony_ciint snd_config_set_integer64(snd_config_t *config, long long value)
2997d5ac70f0Sopenharmony_ci{
2998d5ac70f0Sopenharmony_ci	assert(config);
2999d5ac70f0Sopenharmony_ci	if (config->type != SND_CONFIG_TYPE_INTEGER64)
3000d5ac70f0Sopenharmony_ci		return -EINVAL;
3001d5ac70f0Sopenharmony_ci	config->u.integer64 = value;
3002d5ac70f0Sopenharmony_ci	return 0;
3003d5ac70f0Sopenharmony_ci}
3004d5ac70f0Sopenharmony_ci
3005d5ac70f0Sopenharmony_ci/**
3006d5ac70f0Sopenharmony_ci * \brief Changes the value of a real-number configuration node.
3007d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node.
3008d5ac70f0Sopenharmony_ci * \param value The new value for the node.
3009d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
3010d5ac70f0Sopenharmony_ci *
3011d5ac70f0Sopenharmony_ci * \par Errors:
3012d5ac70f0Sopenharmony_ci * <dl>
3013d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not a real-number node.
3014d5ac70f0Sopenharmony_ci * </dl>
3015d5ac70f0Sopenharmony_ci */
3016d5ac70f0Sopenharmony_ciint snd_config_set_real(snd_config_t *config, double value)
3017d5ac70f0Sopenharmony_ci{
3018d5ac70f0Sopenharmony_ci	assert(config);
3019d5ac70f0Sopenharmony_ci	if (config->type != SND_CONFIG_TYPE_REAL)
3020d5ac70f0Sopenharmony_ci		return -EINVAL;
3021d5ac70f0Sopenharmony_ci	config->u.real = value;
3022d5ac70f0Sopenharmony_ci	return 0;
3023d5ac70f0Sopenharmony_ci}
3024d5ac70f0Sopenharmony_ci
3025d5ac70f0Sopenharmony_ci/**
3026d5ac70f0Sopenharmony_ci * \brief Changes the value of a string configuration node.
3027d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node.
3028d5ac70f0Sopenharmony_ci * \param value The new value for the node.  May be \c NULL.
3029d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
3030d5ac70f0Sopenharmony_ci *
3031d5ac70f0Sopenharmony_ci * This function deletes the old string in the node and stores a copy of
3032d5ac70f0Sopenharmony_ci * \a value string in the node.
3033d5ac70f0Sopenharmony_ci *
3034d5ac70f0Sopenharmony_ci * \par Errors:
3035d5ac70f0Sopenharmony_ci * <dl>
3036d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not a string node.
3037d5ac70f0Sopenharmony_ci * </dl>
3038d5ac70f0Sopenharmony_ci *
3039d5ac70f0Sopenharmony_ci * \par Conforming to:
3040d5ac70f0Sopenharmony_ci * LSB 3.2
3041d5ac70f0Sopenharmony_ci */
3042d5ac70f0Sopenharmony_ciint snd_config_set_string(snd_config_t *config, const char *value)
3043d5ac70f0Sopenharmony_ci{
3044d5ac70f0Sopenharmony_ci	char *new_string;
3045d5ac70f0Sopenharmony_ci	assert(config);
3046d5ac70f0Sopenharmony_ci	if (config->type != SND_CONFIG_TYPE_STRING)
3047d5ac70f0Sopenharmony_ci		return -EINVAL;
3048d5ac70f0Sopenharmony_ci	if (value) {
3049d5ac70f0Sopenharmony_ci		new_string = strdup(value);
3050d5ac70f0Sopenharmony_ci		if (!new_string)
3051d5ac70f0Sopenharmony_ci			return -ENOMEM;
3052d5ac70f0Sopenharmony_ci	} else {
3053d5ac70f0Sopenharmony_ci		new_string = NULL;
3054d5ac70f0Sopenharmony_ci	}
3055d5ac70f0Sopenharmony_ci	free(config->u.string);
3056d5ac70f0Sopenharmony_ci	config->u.string = new_string;
3057d5ac70f0Sopenharmony_ci	return 0;
3058d5ac70f0Sopenharmony_ci}
3059d5ac70f0Sopenharmony_ci
3060d5ac70f0Sopenharmony_ci/**
3061d5ac70f0Sopenharmony_ci * \brief Changes the value of a pointer configuration node.
3062d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node.
3063d5ac70f0Sopenharmony_ci * \param value The new value for the node.  May be \c NULL.
3064d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
3065d5ac70f0Sopenharmony_ci *
3066d5ac70f0Sopenharmony_ci * This function does not free the old pointer in the node.
3067d5ac70f0Sopenharmony_ci *
3068d5ac70f0Sopenharmony_ci * \par Errors:
3069d5ac70f0Sopenharmony_ci * <dl>
3070d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not a pointer node.
3071d5ac70f0Sopenharmony_ci * </dl>
3072d5ac70f0Sopenharmony_ci */
3073d5ac70f0Sopenharmony_ciint snd_config_set_pointer(snd_config_t *config, const void *value)
3074d5ac70f0Sopenharmony_ci{
3075d5ac70f0Sopenharmony_ci	assert(config);
3076d5ac70f0Sopenharmony_ci	if (config->type != SND_CONFIG_TYPE_POINTER)
3077d5ac70f0Sopenharmony_ci		return -EINVAL;
3078d5ac70f0Sopenharmony_ci	config->u.ptr = value;
3079d5ac70f0Sopenharmony_ci	return 0;
3080d5ac70f0Sopenharmony_ci}
3081d5ac70f0Sopenharmony_ci
3082d5ac70f0Sopenharmony_ci/**
3083d5ac70f0Sopenharmony_ci * \brief Changes the value of a configuration node.
3084d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node.
3085d5ac70f0Sopenharmony_ci * \param ascii The new value for the node, as an ASCII string.
3086d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
3087d5ac70f0Sopenharmony_ci *
3088d5ac70f0Sopenharmony_ci * This function changes the node's value to a new value that is parsed
3089d5ac70f0Sopenharmony_ci * from the string \a ascii.  \a ascii must not be \c NULL, not even for
3090d5ac70f0Sopenharmony_ci * a string node.
3091d5ac70f0Sopenharmony_ci *
3092d5ac70f0Sopenharmony_ci * The node's type does not change, i.e., the string must contain a
3093d5ac70f0Sopenharmony_ci * valid value with the same type as the node's type.  For a string
3094d5ac70f0Sopenharmony_ci * node, the node's new value is a copy of \a ascii.
3095d5ac70f0Sopenharmony_ci *
3096d5ac70f0Sopenharmony_ci * \par Errors:
3097d5ac70f0Sopenharmony_ci * <dl>
3098d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not a number or string node.
3099d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>The value in \a ascii cannot be parsed.
3100d5ac70f0Sopenharmony_ci * <dt>-ERANGE<dd>The value in \a ascii is too big for the node's type.
3101d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory.
3102d5ac70f0Sopenharmony_ci * </dl>
3103d5ac70f0Sopenharmony_ci *
3104d5ac70f0Sopenharmony_ci * \par Conforming to:
3105d5ac70f0Sopenharmony_ci * LSB 3.2
3106d5ac70f0Sopenharmony_ci */
3107d5ac70f0Sopenharmony_ciint snd_config_set_ascii(snd_config_t *config, const char *ascii)
3108d5ac70f0Sopenharmony_ci{
3109d5ac70f0Sopenharmony_ci	assert(config && ascii);
3110d5ac70f0Sopenharmony_ci	switch (config->type) {
3111d5ac70f0Sopenharmony_ci	case SND_CONFIG_TYPE_INTEGER:
3112d5ac70f0Sopenharmony_ci		{
3113d5ac70f0Sopenharmony_ci			long i;
3114d5ac70f0Sopenharmony_ci			int err = safe_strtol(ascii, &i);
3115d5ac70f0Sopenharmony_ci			if (err < 0)
3116d5ac70f0Sopenharmony_ci				return err;
3117d5ac70f0Sopenharmony_ci			config->u.integer = i;
3118d5ac70f0Sopenharmony_ci		}
3119d5ac70f0Sopenharmony_ci		break;
3120d5ac70f0Sopenharmony_ci	case SND_CONFIG_TYPE_INTEGER64:
3121d5ac70f0Sopenharmony_ci		{
3122d5ac70f0Sopenharmony_ci			long long i;
3123d5ac70f0Sopenharmony_ci			int err = safe_strtoll(ascii, &i);
3124d5ac70f0Sopenharmony_ci			if (err < 0)
3125d5ac70f0Sopenharmony_ci				return err;
3126d5ac70f0Sopenharmony_ci			config->u.integer64 = i;
3127d5ac70f0Sopenharmony_ci		}
3128d5ac70f0Sopenharmony_ci		break;
3129d5ac70f0Sopenharmony_ci	case SND_CONFIG_TYPE_REAL:
3130d5ac70f0Sopenharmony_ci		{
3131d5ac70f0Sopenharmony_ci			double d;
3132d5ac70f0Sopenharmony_ci			int err = safe_strtod(ascii, &d);
3133d5ac70f0Sopenharmony_ci			if (err < 0)
3134d5ac70f0Sopenharmony_ci				return err;
3135d5ac70f0Sopenharmony_ci			config->u.real = d;
3136d5ac70f0Sopenharmony_ci			break;
3137d5ac70f0Sopenharmony_ci		}
3138d5ac70f0Sopenharmony_ci	case SND_CONFIG_TYPE_STRING:
3139d5ac70f0Sopenharmony_ci		{
3140d5ac70f0Sopenharmony_ci			char *ptr = strdup(ascii);
3141d5ac70f0Sopenharmony_ci			if (ptr == NULL)
3142d5ac70f0Sopenharmony_ci				return -ENOMEM;
3143d5ac70f0Sopenharmony_ci			free(config->u.string);
3144d5ac70f0Sopenharmony_ci			config->u.string = ptr;
3145d5ac70f0Sopenharmony_ci		}
3146d5ac70f0Sopenharmony_ci		break;
3147d5ac70f0Sopenharmony_ci	default:
3148d5ac70f0Sopenharmony_ci		return -EINVAL;
3149d5ac70f0Sopenharmony_ci	}
3150d5ac70f0Sopenharmony_ci	return 0;
3151d5ac70f0Sopenharmony_ci}
3152d5ac70f0Sopenharmony_ci
3153d5ac70f0Sopenharmony_ci/**
3154d5ac70f0Sopenharmony_ci * \brief Returns the value of an integer configuration node.
3155d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration node.
3156d5ac70f0Sopenharmony_ci * \param[out] ptr The node's value.
3157d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
3158d5ac70f0Sopenharmony_ci *
3159d5ac70f0Sopenharmony_ci * \par Errors:
3160d5ac70f0Sopenharmony_ci * <dl>
3161d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not an integer node.
3162d5ac70f0Sopenharmony_ci * </dl>
3163d5ac70f0Sopenharmony_ci *
3164d5ac70f0Sopenharmony_ci * \par Conforming to:
3165d5ac70f0Sopenharmony_ci * LSB 3.2
3166d5ac70f0Sopenharmony_ci */
3167d5ac70f0Sopenharmony_ciint snd_config_get_integer(const snd_config_t *config, long *ptr)
3168d5ac70f0Sopenharmony_ci{
3169d5ac70f0Sopenharmony_ci	assert(config && ptr);
3170d5ac70f0Sopenharmony_ci	if (config->type != SND_CONFIG_TYPE_INTEGER)
3171d5ac70f0Sopenharmony_ci		return -EINVAL;
3172d5ac70f0Sopenharmony_ci	*ptr = config->u.integer;
3173d5ac70f0Sopenharmony_ci	return 0;
3174d5ac70f0Sopenharmony_ci}
3175d5ac70f0Sopenharmony_ci
3176d5ac70f0Sopenharmony_ci/**
3177d5ac70f0Sopenharmony_ci * \brief Returns the value of a 64-bit-integer configuration node.
3178d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration node.
3179d5ac70f0Sopenharmony_ci * \param[out] ptr The node's value.
3180d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
3181d5ac70f0Sopenharmony_ci *
3182d5ac70f0Sopenharmony_ci * \par Errors:
3183d5ac70f0Sopenharmony_ci * <dl>
3184d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not a 64-bit-integer node.
3185d5ac70f0Sopenharmony_ci * </dl>
3186d5ac70f0Sopenharmony_ci *
3187d5ac70f0Sopenharmony_ci * \par Conforming to:
3188d5ac70f0Sopenharmony_ci * LSB 3.2
3189d5ac70f0Sopenharmony_ci */
3190d5ac70f0Sopenharmony_ciint snd_config_get_integer64(const snd_config_t *config, long long *ptr)
3191d5ac70f0Sopenharmony_ci{
3192d5ac70f0Sopenharmony_ci	assert(config && ptr);
3193d5ac70f0Sopenharmony_ci	if (config->type != SND_CONFIG_TYPE_INTEGER64)
3194d5ac70f0Sopenharmony_ci		return -EINVAL;
3195d5ac70f0Sopenharmony_ci	*ptr = config->u.integer64;
3196d5ac70f0Sopenharmony_ci	return 0;
3197d5ac70f0Sopenharmony_ci}
3198d5ac70f0Sopenharmony_ci
3199d5ac70f0Sopenharmony_ci/**
3200d5ac70f0Sopenharmony_ci * \brief Returns the value of a real-number configuration node.
3201d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration node.
3202d5ac70f0Sopenharmony_ci * \param[out] ptr The node's value.
3203d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
3204d5ac70f0Sopenharmony_ci *
3205d5ac70f0Sopenharmony_ci * \par Errors:
3206d5ac70f0Sopenharmony_ci * <dl>
3207d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not a real-number node.
3208d5ac70f0Sopenharmony_ci * </dl>
3209d5ac70f0Sopenharmony_ci */
3210d5ac70f0Sopenharmony_ciint snd_config_get_real(const snd_config_t *config, double *ptr)
3211d5ac70f0Sopenharmony_ci{
3212d5ac70f0Sopenharmony_ci	assert(config && ptr);
3213d5ac70f0Sopenharmony_ci	if (config->type != SND_CONFIG_TYPE_REAL)
3214d5ac70f0Sopenharmony_ci		return -EINVAL;
3215d5ac70f0Sopenharmony_ci	*ptr = config->u.real;
3216d5ac70f0Sopenharmony_ci	return 0;
3217d5ac70f0Sopenharmony_ci}
3218d5ac70f0Sopenharmony_ci
3219d5ac70f0Sopenharmony_ci/**
3220d5ac70f0Sopenharmony_ci * \brief Returns the value of a real or integer configuration node.
3221d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration node.
3222d5ac70f0Sopenharmony_ci * \param[out] ptr The node's value.
3223d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
3224d5ac70f0Sopenharmony_ci *
3225d5ac70f0Sopenharmony_ci * If the node's type is integer or integer64, the value is converted
3226d5ac70f0Sopenharmony_ci * to the \c double type on the fly.
3227d5ac70f0Sopenharmony_ci *
3228d5ac70f0Sopenharmony_ci * \par Errors:
3229d5ac70f0Sopenharmony_ci * <dl>
3230d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not a number node.
3231d5ac70f0Sopenharmony_ci * </dl>
3232d5ac70f0Sopenharmony_ci */
3233d5ac70f0Sopenharmony_ciint snd_config_get_ireal(const snd_config_t *config, double *ptr)
3234d5ac70f0Sopenharmony_ci{
3235d5ac70f0Sopenharmony_ci	assert(config && ptr);
3236d5ac70f0Sopenharmony_ci	if (config->type == SND_CONFIG_TYPE_REAL)
3237d5ac70f0Sopenharmony_ci		*ptr = config->u.real;
3238d5ac70f0Sopenharmony_ci	else if (config->type == SND_CONFIG_TYPE_INTEGER)
3239d5ac70f0Sopenharmony_ci		*ptr = config->u.integer;
3240d5ac70f0Sopenharmony_ci	else if (config->type == SND_CONFIG_TYPE_INTEGER64)
3241d5ac70f0Sopenharmony_ci		*ptr = config->u.integer64;
3242d5ac70f0Sopenharmony_ci	else
3243d5ac70f0Sopenharmony_ci		return -EINVAL;
3244d5ac70f0Sopenharmony_ci	return 0;
3245d5ac70f0Sopenharmony_ci}
3246d5ac70f0Sopenharmony_ci
3247d5ac70f0Sopenharmony_ci/**
3248d5ac70f0Sopenharmony_ci * \brief Returns the value of a string configuration node.
3249d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration node.
3250d5ac70f0Sopenharmony_ci * \param[out] ptr The function puts the node's value at the address
3251d5ac70f0Sopenharmony_ci *                 specified by \a ptr.
3252d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
3253d5ac70f0Sopenharmony_ci *
3254d5ac70f0Sopenharmony_ci * The returned string is owned by the configuration node; the
3255d5ac70f0Sopenharmony_ci * application must not modify or delete it, and the string becomes
3256d5ac70f0Sopenharmony_ci * invalid when the node's value changes or when the node is freed.
3257d5ac70f0Sopenharmony_ci *
3258d5ac70f0Sopenharmony_ci * The string may be \c NULL.
3259d5ac70f0Sopenharmony_ci *
3260d5ac70f0Sopenharmony_ci * \par Errors:
3261d5ac70f0Sopenharmony_ci * <dl>
3262d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not a string node.
3263d5ac70f0Sopenharmony_ci * </dl>
3264d5ac70f0Sopenharmony_ci *
3265d5ac70f0Sopenharmony_ci * \par Conforming to:
3266d5ac70f0Sopenharmony_ci * LSB 3.2
3267d5ac70f0Sopenharmony_ci */
3268d5ac70f0Sopenharmony_ciint snd_config_get_string(const snd_config_t *config, const char **ptr)
3269d5ac70f0Sopenharmony_ci{
3270d5ac70f0Sopenharmony_ci	assert(config && ptr);
3271d5ac70f0Sopenharmony_ci	if (config->type != SND_CONFIG_TYPE_STRING)
3272d5ac70f0Sopenharmony_ci		return -EINVAL;
3273d5ac70f0Sopenharmony_ci	*ptr = config->u.string;
3274d5ac70f0Sopenharmony_ci	return 0;
3275d5ac70f0Sopenharmony_ci}
3276d5ac70f0Sopenharmony_ci
3277d5ac70f0Sopenharmony_ci/**
3278d5ac70f0Sopenharmony_ci * \brief Returns the value of a pointer configuration node.
3279d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration node.
3280d5ac70f0Sopenharmony_ci * \param[out] ptr The function puts the node's value at the address
3281d5ac70f0Sopenharmony_ci *                 specified by \a ptr.
3282d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
3283d5ac70f0Sopenharmony_ci *
3284d5ac70f0Sopenharmony_ci * \par Errors:
3285d5ac70f0Sopenharmony_ci * <dl>
3286d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not a string node.
3287d5ac70f0Sopenharmony_ci * </dl>
3288d5ac70f0Sopenharmony_ci */
3289d5ac70f0Sopenharmony_ciint snd_config_get_pointer(const snd_config_t *config, const void **ptr)
3290d5ac70f0Sopenharmony_ci{
3291d5ac70f0Sopenharmony_ci	assert(config && ptr);
3292d5ac70f0Sopenharmony_ci	if (config->type != SND_CONFIG_TYPE_POINTER)
3293d5ac70f0Sopenharmony_ci		return -EINVAL;
3294d5ac70f0Sopenharmony_ci	*ptr = config->u.ptr;
3295d5ac70f0Sopenharmony_ci	return 0;
3296d5ac70f0Sopenharmony_ci}
3297d5ac70f0Sopenharmony_ci
3298d5ac70f0Sopenharmony_ci/**
3299d5ac70f0Sopenharmony_ci * \brief Returns the value of a configuration node as a string.
3300d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration node.
3301d5ac70f0Sopenharmony_ci * \param[out] ascii The function puts the pointer to the returned
3302d5ac70f0Sopenharmony_ci *                   string at the address specified by \a ascii.
3303d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
3304d5ac70f0Sopenharmony_ci *
3305d5ac70f0Sopenharmony_ci * This function dynamically allocates the returned string.  The
3306d5ac70f0Sopenharmony_ci * application is responsible for deleting it with \c free() when it is
3307d5ac70f0Sopenharmony_ci * no longer used.
3308d5ac70f0Sopenharmony_ci *
3309d5ac70f0Sopenharmony_ci * For a string node with \c NULL value, the returned string is \c NULL.
3310d5ac70f0Sopenharmony_ci *
3311d5ac70f0Sopenharmony_ci * Supported node types are #SND_CONFIG_TYPE_INTEGER,
3312d5ac70f0Sopenharmony_ci * #SND_CONFIG_TYPE_INTEGER64, #SND_CONFIG_TYPE_REAL, and
3313d5ac70f0Sopenharmony_ci * #SND_CONFIG_TYPE_STRING.
3314d5ac70f0Sopenharmony_ci *
3315d5ac70f0Sopenharmony_ci * \par Errors:
3316d5ac70f0Sopenharmony_ci * <dl>
3317d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>\a config is not a (64-bit) integer or real number or
3318d5ac70f0Sopenharmony_ci *                string node.
3319d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory.
3320d5ac70f0Sopenharmony_ci * </dl>
3321d5ac70f0Sopenharmony_ci *
3322d5ac70f0Sopenharmony_ci * \par Conforming to:
3323d5ac70f0Sopenharmony_ci * LSB 3.2
3324d5ac70f0Sopenharmony_ci */
3325d5ac70f0Sopenharmony_ciint snd_config_get_ascii(const snd_config_t *config, char **ascii)
3326d5ac70f0Sopenharmony_ci{
3327d5ac70f0Sopenharmony_ci	assert(config && ascii);
3328d5ac70f0Sopenharmony_ci	switch (config->type) {
3329d5ac70f0Sopenharmony_ci	case SND_CONFIG_TYPE_INTEGER:
3330d5ac70f0Sopenharmony_ci		{
3331d5ac70f0Sopenharmony_ci			char res[12];
3332d5ac70f0Sopenharmony_ci			int err;
3333d5ac70f0Sopenharmony_ci			err = snprintf(res, sizeof(res), "%li", config->u.integer);
3334d5ac70f0Sopenharmony_ci			if (err < 0 || err == sizeof(res)) {
3335d5ac70f0Sopenharmony_ci				assert(0);
3336d5ac70f0Sopenharmony_ci				return -ENOMEM;
3337d5ac70f0Sopenharmony_ci			}
3338d5ac70f0Sopenharmony_ci			*ascii = strdup(res);
3339d5ac70f0Sopenharmony_ci		}
3340d5ac70f0Sopenharmony_ci		break;
3341d5ac70f0Sopenharmony_ci	case SND_CONFIG_TYPE_INTEGER64:
3342d5ac70f0Sopenharmony_ci		{
3343d5ac70f0Sopenharmony_ci			char res[32];
3344d5ac70f0Sopenharmony_ci			int err;
3345d5ac70f0Sopenharmony_ci			err = snprintf(res, sizeof(res), "%lli", config->u.integer64);
3346d5ac70f0Sopenharmony_ci			if (err < 0 || err == sizeof(res)) {
3347d5ac70f0Sopenharmony_ci				assert(0);
3348d5ac70f0Sopenharmony_ci				return -ENOMEM;
3349d5ac70f0Sopenharmony_ci			}
3350d5ac70f0Sopenharmony_ci			*ascii = strdup(res);
3351d5ac70f0Sopenharmony_ci		}
3352d5ac70f0Sopenharmony_ci		break;
3353d5ac70f0Sopenharmony_ci	case SND_CONFIG_TYPE_REAL:
3354d5ac70f0Sopenharmony_ci		{
3355d5ac70f0Sopenharmony_ci			char res[32];
3356d5ac70f0Sopenharmony_ci			int err;
3357d5ac70f0Sopenharmony_ci			err = snprintf(res, sizeof(res), "%-16g", config->u.real);
3358d5ac70f0Sopenharmony_ci			if (err < 0 || err == sizeof(res)) {
3359d5ac70f0Sopenharmony_ci				assert(0);
3360d5ac70f0Sopenharmony_ci				return -ENOMEM;
3361d5ac70f0Sopenharmony_ci			}
3362d5ac70f0Sopenharmony_ci			if (res[0]) {		/* trim the string */
3363d5ac70f0Sopenharmony_ci				char *ptr;
3364d5ac70f0Sopenharmony_ci				ptr = res + strlen(res) - 1;
3365d5ac70f0Sopenharmony_ci				while (ptr != res && *ptr == ' ')
3366d5ac70f0Sopenharmony_ci					ptr--;
3367d5ac70f0Sopenharmony_ci				if (*ptr != ' ')
3368d5ac70f0Sopenharmony_ci					ptr++;
3369d5ac70f0Sopenharmony_ci				*ptr = '\0';
3370d5ac70f0Sopenharmony_ci			}
3371d5ac70f0Sopenharmony_ci			*ascii = strdup(res);
3372d5ac70f0Sopenharmony_ci		}
3373d5ac70f0Sopenharmony_ci		break;
3374d5ac70f0Sopenharmony_ci	case SND_CONFIG_TYPE_STRING:
3375d5ac70f0Sopenharmony_ci		if (config->u.string)
3376d5ac70f0Sopenharmony_ci			*ascii = strdup(config->u.string);
3377d5ac70f0Sopenharmony_ci		else {
3378d5ac70f0Sopenharmony_ci			*ascii = NULL;
3379d5ac70f0Sopenharmony_ci			return 0;
3380d5ac70f0Sopenharmony_ci		}
3381d5ac70f0Sopenharmony_ci		break;
3382d5ac70f0Sopenharmony_ci	default:
3383d5ac70f0Sopenharmony_ci		return -EINVAL;
3384d5ac70f0Sopenharmony_ci	}
3385d5ac70f0Sopenharmony_ci	if (*ascii == NULL)
3386d5ac70f0Sopenharmony_ci		return -ENOMEM;
3387d5ac70f0Sopenharmony_ci	return 0;
3388d5ac70f0Sopenharmony_ci}
3389d5ac70f0Sopenharmony_ci
3390d5ac70f0Sopenharmony_ci/**
3391d5ac70f0Sopenharmony_ci * \brief Compares the id of a configuration node to a given string.
3392d5ac70f0Sopenharmony_ci * \param config Handle to the configuration node.
3393d5ac70f0Sopenharmony_ci * \param id ASCII id.
3394d5ac70f0Sopenharmony_ci * \return The same value as the result of the \c strcmp function, i.e.,
3395d5ac70f0Sopenharmony_ci *         less than zero if \a config's id is lexicographically less
3396d5ac70f0Sopenharmony_ci *         than \a id, zero if \a config's id is equal to id, greater
3397d5ac70f0Sopenharmony_ci *         than zero otherwise.
3398d5ac70f0Sopenharmony_ci */
3399d5ac70f0Sopenharmony_ciint snd_config_test_id(const snd_config_t *config, const char *id)
3400d5ac70f0Sopenharmony_ci{
3401d5ac70f0Sopenharmony_ci	assert(config && id);
3402d5ac70f0Sopenharmony_ci	if (config->id)
3403d5ac70f0Sopenharmony_ci		return strcmp(config->id, id);
3404d5ac70f0Sopenharmony_ci	else
3405d5ac70f0Sopenharmony_ci		return -1;
3406d5ac70f0Sopenharmony_ci}
3407d5ac70f0Sopenharmony_ci
3408d5ac70f0Sopenharmony_ci/**
3409d5ac70f0Sopenharmony_ci * \brief Dumps the contents of a configuration node or tree.
3410d5ac70f0Sopenharmony_ci * \param config Handle to the (root) configuration node.
3411d5ac70f0Sopenharmony_ci * \param out Output handle.
3412d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
3413d5ac70f0Sopenharmony_ci *
3414d5ac70f0Sopenharmony_ci * This function writes a textual representation of \a config's value to
3415d5ac70f0Sopenharmony_ci * the output \a out.
3416d5ac70f0Sopenharmony_ci *
3417d5ac70f0Sopenharmony_ci * \par Errors:
3418d5ac70f0Sopenharmony_ci * <dl>
3419d5ac70f0Sopenharmony_ci * <dt>-EINVAL<dd>A node in the tree has a type that cannot be printed,
3420d5ac70f0Sopenharmony_ci *                i.e., #SND_CONFIG_TYPE_POINTER.
3421d5ac70f0Sopenharmony_ci * </dl>
3422d5ac70f0Sopenharmony_ci *
3423d5ac70f0Sopenharmony_ci * \par Conforming to:
3424d5ac70f0Sopenharmony_ci * LSB 3.2
3425d5ac70f0Sopenharmony_ci */
3426d5ac70f0Sopenharmony_ciint snd_config_save(snd_config_t *config, snd_output_t *out)
3427d5ac70f0Sopenharmony_ci{
3428d5ac70f0Sopenharmony_ci	assert(config && out);
3429d5ac70f0Sopenharmony_ci	if (config->type == SND_CONFIG_TYPE_COMPOUND) {
3430d5ac70f0Sopenharmony_ci		int array = snd_config_is_array(config);
3431d5ac70f0Sopenharmony_ci		return _snd_config_save_children(config, out, 0, 0, array);
3432d5ac70f0Sopenharmony_ci	} else {
3433d5ac70f0Sopenharmony_ci		return _snd_config_save_node_value(config, out, 0);
3434d5ac70f0Sopenharmony_ci	}
3435d5ac70f0Sopenharmony_ci}
3436d5ac70f0Sopenharmony_ci
3437d5ac70f0Sopenharmony_ci/*
3438d5ac70f0Sopenharmony_ci *  *** search macros ***
3439d5ac70f0Sopenharmony_ci */
3440d5ac70f0Sopenharmony_ci
3441d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN
3442d5ac70f0Sopenharmony_ci
3443d5ac70f0Sopenharmony_ci#define SND_CONFIG_SEARCH(config, key, result, extra_code) \
3444d5ac70f0Sopenharmony_ci{ \
3445d5ac70f0Sopenharmony_ci	snd_config_t *n; \
3446d5ac70f0Sopenharmony_ci	int err; \
3447d5ac70f0Sopenharmony_ci	const char *p; \
3448d5ac70f0Sopenharmony_ci	assert(config && key); \
3449d5ac70f0Sopenharmony_ci	while (1) { \
3450d5ac70f0Sopenharmony_ci		if (config->type != SND_CONFIG_TYPE_COMPOUND) \
3451d5ac70f0Sopenharmony_ci			return -ENOENT; \
3452d5ac70f0Sopenharmony_ci		{ extra_code ; } \
3453d5ac70f0Sopenharmony_ci		p = strchr(key, '.'); \
3454d5ac70f0Sopenharmony_ci		if (p) { \
3455d5ac70f0Sopenharmony_ci			err = _snd_config_search(config, key, p - key, &n); \
3456d5ac70f0Sopenharmony_ci			if (err < 0) \
3457d5ac70f0Sopenharmony_ci				return err; \
3458d5ac70f0Sopenharmony_ci			config = n; \
3459d5ac70f0Sopenharmony_ci			key = p + 1; \
3460d5ac70f0Sopenharmony_ci		} else \
3461d5ac70f0Sopenharmony_ci			return _snd_config_search(config, key, -1, result); \
3462d5ac70f0Sopenharmony_ci	} \
3463d5ac70f0Sopenharmony_ci}
3464d5ac70f0Sopenharmony_ci
3465d5ac70f0Sopenharmony_ci#define SND_CONFIG_SEARCHA(root, config, key, result, fcn, extra_code) \
3466d5ac70f0Sopenharmony_ci{ \
3467d5ac70f0Sopenharmony_ci	snd_config_t *n; \
3468d5ac70f0Sopenharmony_ci	int err; \
3469d5ac70f0Sopenharmony_ci	const char *p; \
3470d5ac70f0Sopenharmony_ci	assert(config && key); \
3471d5ac70f0Sopenharmony_ci	while (1) { \
3472d5ac70f0Sopenharmony_ci		if (config->type != SND_CONFIG_TYPE_COMPOUND) { \
3473d5ac70f0Sopenharmony_ci			if (snd_config_get_string(config, &p) < 0) \
3474d5ac70f0Sopenharmony_ci				return -ENOENT; \
3475d5ac70f0Sopenharmony_ci			err = fcn(root, root, p, &config); \
3476d5ac70f0Sopenharmony_ci			if (err < 0) \
3477d5ac70f0Sopenharmony_ci				return err; \
3478d5ac70f0Sopenharmony_ci		} \
3479d5ac70f0Sopenharmony_ci		{ extra_code ; } \
3480d5ac70f0Sopenharmony_ci		p = strchr(key, '.'); \
3481d5ac70f0Sopenharmony_ci		if (p) { \
3482d5ac70f0Sopenharmony_ci			err = _snd_config_search(config, key, p - key, &n); \
3483d5ac70f0Sopenharmony_ci			if (err < 0) \
3484d5ac70f0Sopenharmony_ci				return err; \
3485d5ac70f0Sopenharmony_ci			config = n; \
3486d5ac70f0Sopenharmony_ci			key = p + 1; \
3487d5ac70f0Sopenharmony_ci		} else \
3488d5ac70f0Sopenharmony_ci			return _snd_config_search(config, key, -1, result); \
3489d5ac70f0Sopenharmony_ci	} \
3490d5ac70f0Sopenharmony_ci}
3491d5ac70f0Sopenharmony_ci
3492d5ac70f0Sopenharmony_ci#define SND_CONFIG_SEARCHV(config, result, fcn) \
3493d5ac70f0Sopenharmony_ci{ \
3494d5ac70f0Sopenharmony_ci	snd_config_t *n; \
3495d5ac70f0Sopenharmony_ci	va_list arg; \
3496d5ac70f0Sopenharmony_ci	assert(config); \
3497d5ac70f0Sopenharmony_ci	va_start(arg, result); \
3498d5ac70f0Sopenharmony_ci	while (1) { \
3499d5ac70f0Sopenharmony_ci		const char *k = va_arg(arg, const char *); \
3500d5ac70f0Sopenharmony_ci		int err; \
3501d5ac70f0Sopenharmony_ci		if (!k) \
3502d5ac70f0Sopenharmony_ci			break; \
3503d5ac70f0Sopenharmony_ci		err = fcn(config, k, &n); \
3504d5ac70f0Sopenharmony_ci		if (err < 0) { \
3505d5ac70f0Sopenharmony_ci			va_end(arg); \
3506d5ac70f0Sopenharmony_ci			return err; \
3507d5ac70f0Sopenharmony_ci		} \
3508d5ac70f0Sopenharmony_ci		config = n; \
3509d5ac70f0Sopenharmony_ci	} \
3510d5ac70f0Sopenharmony_ci	va_end(arg); \
3511d5ac70f0Sopenharmony_ci	if (result) \
3512d5ac70f0Sopenharmony_ci		*result = n; \
3513d5ac70f0Sopenharmony_ci	return 0; \
3514d5ac70f0Sopenharmony_ci}
3515d5ac70f0Sopenharmony_ci
3516d5ac70f0Sopenharmony_ci#define SND_CONFIG_SEARCHVA(root, config, result, fcn) \
3517d5ac70f0Sopenharmony_ci{ \
3518d5ac70f0Sopenharmony_ci	snd_config_t *n; \
3519d5ac70f0Sopenharmony_ci	va_list arg; \
3520d5ac70f0Sopenharmony_ci	assert(config); \
3521d5ac70f0Sopenharmony_ci	va_start(arg, result); \
3522d5ac70f0Sopenharmony_ci	while (1) { \
3523d5ac70f0Sopenharmony_ci		const char *k = va_arg(arg, const char *); \
3524d5ac70f0Sopenharmony_ci		int err; \
3525d5ac70f0Sopenharmony_ci		if (!k) \
3526d5ac70f0Sopenharmony_ci			break; \
3527d5ac70f0Sopenharmony_ci		err = fcn(root, config, k, &n); \
3528d5ac70f0Sopenharmony_ci		if (err < 0) { \
3529d5ac70f0Sopenharmony_ci			va_end(arg); \
3530d5ac70f0Sopenharmony_ci			return err; \
3531d5ac70f0Sopenharmony_ci		} \
3532d5ac70f0Sopenharmony_ci		config = n; \
3533d5ac70f0Sopenharmony_ci	} \
3534d5ac70f0Sopenharmony_ci	va_end(arg); \
3535d5ac70f0Sopenharmony_ci	if (result) \
3536d5ac70f0Sopenharmony_ci		*result = n; \
3537d5ac70f0Sopenharmony_ci	return 0; \
3538d5ac70f0Sopenharmony_ci}
3539d5ac70f0Sopenharmony_ci
3540d5ac70f0Sopenharmony_ci#define SND_CONFIG_SEARCH_ALIAS(config, base, key, result, fcn1, fcn2) \
3541d5ac70f0Sopenharmony_ci{ \
3542d5ac70f0Sopenharmony_ci	snd_config_t *res = NULL; \
3543d5ac70f0Sopenharmony_ci	char *old_key; \
3544d5ac70f0Sopenharmony_ci	int err, first = 1, maxloop = 1000; \
3545d5ac70f0Sopenharmony_ci	assert(config && key); \
3546d5ac70f0Sopenharmony_ci	while (1) { \
3547d5ac70f0Sopenharmony_ci		old_key = strdup(key); \
3548d5ac70f0Sopenharmony_ci		if (old_key == NULL) { \
3549d5ac70f0Sopenharmony_ci			err = -ENOMEM; \
3550d5ac70f0Sopenharmony_ci			res = NULL; \
3551d5ac70f0Sopenharmony_ci			break; \
3552d5ac70f0Sopenharmony_ci		} \
3553d5ac70f0Sopenharmony_ci		err = first && base ? -EIO : fcn1(config, config, key, &res); \
3554d5ac70f0Sopenharmony_ci		if (err < 0) { \
3555d5ac70f0Sopenharmony_ci			if (!base) \
3556d5ac70f0Sopenharmony_ci				break; \
3557d5ac70f0Sopenharmony_ci			err = fcn2(config, config, &res, base, key, NULL); \
3558d5ac70f0Sopenharmony_ci			if (err < 0) \
3559d5ac70f0Sopenharmony_ci				break; \
3560d5ac70f0Sopenharmony_ci		} \
3561d5ac70f0Sopenharmony_ci		if (snd_config_get_string(res, &key) < 0) \
3562d5ac70f0Sopenharmony_ci			break; \
3563d5ac70f0Sopenharmony_ci		assert(key); \
3564d5ac70f0Sopenharmony_ci		if (!first && (strcmp(key, old_key) == 0 || maxloop <= 0)) { \
3565d5ac70f0Sopenharmony_ci			if (maxloop == 0) \
3566d5ac70f0Sopenharmony_ci				SNDERR("maximum loop count reached (circular configuration?)"); \
3567d5ac70f0Sopenharmony_ci			else \
3568d5ac70f0Sopenharmony_ci				SNDERR("key %s refers to itself", key); \
3569d5ac70f0Sopenharmony_ci			err = -EINVAL; \
3570d5ac70f0Sopenharmony_ci			res = NULL; \
3571d5ac70f0Sopenharmony_ci			break; \
3572d5ac70f0Sopenharmony_ci		} \
3573d5ac70f0Sopenharmony_ci		free(old_key); \
3574d5ac70f0Sopenharmony_ci		first = 0; \
3575d5ac70f0Sopenharmony_ci		maxloop--; \
3576d5ac70f0Sopenharmony_ci	} \
3577d5ac70f0Sopenharmony_ci	free(old_key); \
3578d5ac70f0Sopenharmony_ci	if (!res) \
3579d5ac70f0Sopenharmony_ci		return err; \
3580d5ac70f0Sopenharmony_ci	if (result) \
3581d5ac70f0Sopenharmony_ci		*result = res; \
3582d5ac70f0Sopenharmony_ci	return 0; \
3583d5ac70f0Sopenharmony_ci}
3584d5ac70f0Sopenharmony_ci
3585d5ac70f0Sopenharmony_ci#endif /* DOC_HIDDEN */
3586d5ac70f0Sopenharmony_ci
3587d5ac70f0Sopenharmony_ci/**
3588d5ac70f0Sopenharmony_ci * \brief Searches for a node in a configuration tree.
3589d5ac70f0Sopenharmony_ci * \param[in] config Handle to the root of the configuration (sub)tree to search.
3590d5ac70f0Sopenharmony_ci * \param[in] key Search key: one or more node ids, separated with dots.
3591d5ac70f0Sopenharmony_ci * \param[out] result When \a result != \c NULL, the function puts the
3592d5ac70f0Sopenharmony_ci *                    handle to the node found at the address specified
3593d5ac70f0Sopenharmony_ci *                    by \a result.
3594d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
3595d5ac70f0Sopenharmony_ci *
3596d5ac70f0Sopenharmony_ci * This function searches for a child node of \a config that is
3597d5ac70f0Sopenharmony_ci * identified by \a key, which contains either the id of a direct child
3598d5ac70f0Sopenharmony_ci * node of \a config, or a series of ids, separated with dots, where
3599d5ac70f0Sopenharmony_ci * each id specifies a node that is contained in the previous compound
3600d5ac70f0Sopenharmony_ci * node.
3601d5ac70f0Sopenharmony_ci *
3602d5ac70f0Sopenharmony_ci * In the following example, the comment after each node shows the
3603d5ac70f0Sopenharmony_ci * search key to find that node, assuming that \a config is a handle to
3604d5ac70f0Sopenharmony_ci * the compound node with id \c config:
3605d5ac70f0Sopenharmony_ci * \code
3606d5ac70f0Sopenharmony_ci * config {
3607d5ac70f0Sopenharmony_ci *     a 42               # "a"
3608d5ac70f0Sopenharmony_ci *     b {                # "b"
3609d5ac70f0Sopenharmony_ci *         c "cee"        # "b.c"
3610d5ac70f0Sopenharmony_ci *         d {            # "b.d"
3611d5ac70f0Sopenharmony_ci *             e 2.71828  # "b.d.e"
3612d5ac70f0Sopenharmony_ci *         }
3613d5ac70f0Sopenharmony_ci *     }
3614d5ac70f0Sopenharmony_ci * }
3615d5ac70f0Sopenharmony_ci * \endcode
3616d5ac70f0Sopenharmony_ci *
3617d5ac70f0Sopenharmony_ci * \par Errors:
3618d5ac70f0Sopenharmony_ci * <dl>
3619d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>An id in \a key does not exist.
3620d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is
3621d5ac70f0Sopenharmony_ci *                not a compound node.
3622d5ac70f0Sopenharmony_ci * </dl>
3623d5ac70f0Sopenharmony_ci *
3624d5ac70f0Sopenharmony_ci * \par Conforming to:
3625d5ac70f0Sopenharmony_ci * LSB 3.2
3626d5ac70f0Sopenharmony_ci */
3627d5ac70f0Sopenharmony_ciint snd_config_search(snd_config_t *config, const char *key, snd_config_t **result)
3628d5ac70f0Sopenharmony_ci{
3629d5ac70f0Sopenharmony_ci	SND_CONFIG_SEARCH(config, key, result, );
3630d5ac70f0Sopenharmony_ci}
3631d5ac70f0Sopenharmony_ci
3632d5ac70f0Sopenharmony_ci/**
3633d5ac70f0Sopenharmony_ci * \brief Searches for a node in a configuration tree, expanding aliases.
3634d5ac70f0Sopenharmony_ci * \param[in] root Handle to the root configuration node containing
3635d5ac70f0Sopenharmony_ci *                 alias definitions.
3636d5ac70f0Sopenharmony_ci * \param[in] config Handle to the root of the configuration (sub)tree to search.
3637d5ac70f0Sopenharmony_ci * \param[in] key Search key: one or more node keys, separated with dots.
3638d5ac70f0Sopenharmony_ci * \param[out] result When \a result != \c NULL, the function puts the
3639d5ac70f0Sopenharmony_ci *                    handle to the node found at the address specified
3640d5ac70f0Sopenharmony_ci *                    by \a result.
3641d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
3642d5ac70f0Sopenharmony_ci *
3643d5ac70f0Sopenharmony_ci * This functions searches for a child node of \a config like
3644d5ac70f0Sopenharmony_ci * #snd_config_search.  However, any compound node can also be
3645d5ac70f0Sopenharmony_ci * identified by an alias, which is a string node whose value is taken
3646d5ac70f0Sopenharmony_ci * as the id of a compound node below \a root.
3647d5ac70f0Sopenharmony_ci *
3648d5ac70f0Sopenharmony_ci * \a root must be a compound node.
3649d5ac70f0Sopenharmony_ci * \a root and \a config may be the same node.
3650d5ac70f0Sopenharmony_ci *
3651d5ac70f0Sopenharmony_ci * For example, with the following configuration, the call
3652d5ac70f0Sopenharmony_ci * \code
3653d5ac70f0Sopenharmony_ci * snd_config_searcha(root, config, "a.b.c.d", &result);
3654d5ac70f0Sopenharmony_ci * \endcode
3655d5ac70f0Sopenharmony_ci * would return the node with id \c d:
3656d5ac70f0Sopenharmony_ci * \code
3657d5ac70f0Sopenharmony_ci * config {
3658d5ac70f0Sopenharmony_ci *     a {
3659d5ac70f0Sopenharmony_ci *         b bb
3660d5ac70f0Sopenharmony_ci *     }
3661d5ac70f0Sopenharmony_ci * }
3662d5ac70f0Sopenharmony_ci * root {
3663d5ac70f0Sopenharmony_ci *     bb {
3664d5ac70f0Sopenharmony_ci *         c cc
3665d5ac70f0Sopenharmony_ci *     }
3666d5ac70f0Sopenharmony_ci *     cc ccc
3667d5ac70f0Sopenharmony_ci *     ccc {
3668d5ac70f0Sopenharmony_ci *         d {
3669d5ac70f0Sopenharmony_ci *             x "icks"
3670d5ac70f0Sopenharmony_ci *         }
3671d5ac70f0Sopenharmony_ci *     }
3672d5ac70f0Sopenharmony_ci * }
3673d5ac70f0Sopenharmony_ci * \endcode
3674d5ac70f0Sopenharmony_ci *
3675d5ac70f0Sopenharmony_ci * \par Errors:
3676d5ac70f0Sopenharmony_ci * <dl>
3677d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>An id in \a key or an alias id does not exist.
3678d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is
3679d5ac70f0Sopenharmony_ci *                not a compound or string node.
3680d5ac70f0Sopenharmony_ci * </dl>
3681d5ac70f0Sopenharmony_ci */
3682d5ac70f0Sopenharmony_ciint snd_config_searcha(snd_config_t *root, snd_config_t *config, const char *key, snd_config_t **result)
3683d5ac70f0Sopenharmony_ci{
3684d5ac70f0Sopenharmony_ci	SND_CONFIG_SEARCHA(root, config, key, result, snd_config_searcha, );
3685d5ac70f0Sopenharmony_ci}
3686d5ac70f0Sopenharmony_ci
3687d5ac70f0Sopenharmony_ci/**
3688d5ac70f0Sopenharmony_ci * \brief Searches for a node in a configuration tree.
3689d5ac70f0Sopenharmony_ci * \param[in] config Handle to the root of the configuration (sub)tree to search.
3690d5ac70f0Sopenharmony_ci * \param[out] result When \a result != \c NULL, the function puts the
3691d5ac70f0Sopenharmony_ci *                    handle to the node found at the address specified
3692d5ac70f0Sopenharmony_ci *                    by \a result.
3693d5ac70f0Sopenharmony_ci * \param[in] ... One or more concatenated dot-separated search keys,
3694d5ac70f0Sopenharmony_ci *                terminated with \c NULL.
3695d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
3696d5ac70f0Sopenharmony_ci *
3697d5ac70f0Sopenharmony_ci * This functions searches for a child node of \a config like
3698d5ac70f0Sopenharmony_ci * #snd_config_search, but the search key is the concatenation of all
3699d5ac70f0Sopenharmony_ci * passed search key strings.  For example, the call
3700d5ac70f0Sopenharmony_ci * \code
3701d5ac70f0Sopenharmony_ci * snd_config_searchv(cfg, &res, "a", "b.c", "d.e", NULL);
3702d5ac70f0Sopenharmony_ci * \endcode
3703d5ac70f0Sopenharmony_ci * is equivalent to the call
3704d5ac70f0Sopenharmony_ci * \code
3705d5ac70f0Sopenharmony_ci * snd_config_search(cfg, "a.b.c.d.e", &res);
3706d5ac70f0Sopenharmony_ci * \endcode
3707d5ac70f0Sopenharmony_ci *
3708d5ac70f0Sopenharmony_ci * \par Errors:
3709d5ac70f0Sopenharmony_ci * <dl>
3710d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>An id in a search key does not exist.
3711d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is
3712d5ac70f0Sopenharmony_ci *                not a compound node.
3713d5ac70f0Sopenharmony_ci * </dl>
3714d5ac70f0Sopenharmony_ci *
3715d5ac70f0Sopenharmony_ci * \par Conforming to:
3716d5ac70f0Sopenharmony_ci * LSB 3.2
3717d5ac70f0Sopenharmony_ci */
3718d5ac70f0Sopenharmony_ciint snd_config_searchv(snd_config_t *config, snd_config_t **result, ...)
3719d5ac70f0Sopenharmony_ci{
3720d5ac70f0Sopenharmony_ci	SND_CONFIG_SEARCHV(config, result, snd_config_search);
3721d5ac70f0Sopenharmony_ci}
3722d5ac70f0Sopenharmony_ci
3723d5ac70f0Sopenharmony_ci/**
3724d5ac70f0Sopenharmony_ci * \brief Searches for a node in a configuration tree, expanding aliases.
3725d5ac70f0Sopenharmony_ci * \param[in] root Handle to the root configuration node containing
3726d5ac70f0Sopenharmony_ci *                 alias definitions.
3727d5ac70f0Sopenharmony_ci * \param[in] config Handle to the root of the configuration (sub)tree to search.
3728d5ac70f0Sopenharmony_ci * \param[out] result When \a result != \c NULL, the function puts the
3729d5ac70f0Sopenharmony_ci *                    handle to the node found at the address specified
3730d5ac70f0Sopenharmony_ci *                    by \a result.
3731d5ac70f0Sopenharmony_ci * \param[in] ... One or more concatenated dot separated search keys,
3732d5ac70f0Sopenharmony_ci *                terminated with \c NULL.
3733d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
3734d5ac70f0Sopenharmony_ci *
3735d5ac70f0Sopenharmony_ci * This function searches for a child node of \a config, allowing
3736d5ac70f0Sopenharmony_ci * aliases, like #snd_config_searcha, but the search key is the
3737d5ac70f0Sopenharmony_ci * concatenation of all passed seach key strings, like with
3738d5ac70f0Sopenharmony_ci * #snd_config_searchv.
3739d5ac70f0Sopenharmony_ci *
3740d5ac70f0Sopenharmony_ci * \par Errors:
3741d5ac70f0Sopenharmony_ci * <dl>
3742d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>An id in a search key does not exist.
3743d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is
3744d5ac70f0Sopenharmony_ci *                not a compound or string node.
3745d5ac70f0Sopenharmony_ci * </dl>
3746d5ac70f0Sopenharmony_ci */
3747d5ac70f0Sopenharmony_ciint snd_config_searchva(snd_config_t *root, snd_config_t *config, snd_config_t **result, ...)
3748d5ac70f0Sopenharmony_ci{
3749d5ac70f0Sopenharmony_ci	SND_CONFIG_SEARCHVA(root, config, result, snd_config_searcha);
3750d5ac70f0Sopenharmony_ci}
3751d5ac70f0Sopenharmony_ci
3752d5ac70f0Sopenharmony_ci/**
3753d5ac70f0Sopenharmony_ci * \brief Searches for a node in a configuration tree, expanding aliases.
3754d5ac70f0Sopenharmony_ci * \param[in] config Handle to the root of the configuration (sub)tree to search.
3755d5ac70f0Sopenharmony_ci * \param[in] base Search key base, or \c NULL.
3756d5ac70f0Sopenharmony_ci * \param[in] key Search key suffix.
3757d5ac70f0Sopenharmony_ci * \param[out] result When \a result != \c NULL, the function puts the
3758d5ac70f0Sopenharmony_ci *                    handle to the node found at the address specified
3759d5ac70f0Sopenharmony_ci *                    by \a result.
3760d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
3761d5ac70f0Sopenharmony_ci *
3762d5ac70f0Sopenharmony_ci * This functions searches for a child node of \a config, allowing
3763d5ac70f0Sopenharmony_ci * aliases, like #snd_config_searcha.  However, alias definitions are
3764d5ac70f0Sopenharmony_ci * searched below \a config (there is no separate \a root parameter),
3765d5ac70f0Sopenharmony_ci * and \a base specifies a seach key that identifies a compound node
3766d5ac70f0Sopenharmony_ci * that is used to search for an alias definitions that is not found
3767d5ac70f0Sopenharmony_ci * directly below \a config and that does not contain a period.  In
3768d5ac70f0Sopenharmony_ci * other words, when \c "id" is not found in \a config, this function
3769d5ac70f0Sopenharmony_ci * also tries \c "base.id".
3770d5ac70f0Sopenharmony_ci *
3771d5ac70f0Sopenharmony_ci * \par Errors:
3772d5ac70f0Sopenharmony_ci * <dl>
3773d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>An id in \a key or an alias id does not exist.
3774d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is
3775d5ac70f0Sopenharmony_ci *                not a compound or string node.
3776d5ac70f0Sopenharmony_ci * </dl>
3777d5ac70f0Sopenharmony_ci */
3778d5ac70f0Sopenharmony_ciint snd_config_search_alias(snd_config_t *config,
3779d5ac70f0Sopenharmony_ci			    const char *base, const char *key,
3780d5ac70f0Sopenharmony_ci			    snd_config_t **result)
3781d5ac70f0Sopenharmony_ci{
3782d5ac70f0Sopenharmony_ci	SND_CONFIG_SEARCH_ALIAS(config, base, key, result,
3783d5ac70f0Sopenharmony_ci				snd_config_searcha, snd_config_searchva);
3784d5ac70f0Sopenharmony_ci}
3785d5ac70f0Sopenharmony_ci
3786d5ac70f0Sopenharmony_cistatic int snd_config_hooks(snd_config_t *config, snd_config_t *private_data);
3787d5ac70f0Sopenharmony_ci
3788d5ac70f0Sopenharmony_ci/**
3789d5ac70f0Sopenharmony_ci * \brief Searches for a node in a configuration tree and expands hooks.
3790d5ac70f0Sopenharmony_ci * \param[in,out] config Handle to the root of the configuration
3791d5ac70f0Sopenharmony_ci *                       (sub)tree to search.
3792d5ac70f0Sopenharmony_ci * \param[in] key Search key: one or more node keys, separated with dots.
3793d5ac70f0Sopenharmony_ci * \param[out] result The function puts the handle to the node found at
3794d5ac70f0Sopenharmony_ci *                    the address specified by \a result.
3795d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
3796d5ac70f0Sopenharmony_ci *
3797d5ac70f0Sopenharmony_ci * This functions searches for a child node of \a config like
3798d5ac70f0Sopenharmony_ci * #snd_config_search, but any compound nodes to be searched that
3799d5ac70f0Sopenharmony_ci * contain hooks are modified by the respective hook functions.
3800d5ac70f0Sopenharmony_ci *
3801d5ac70f0Sopenharmony_ci * \par Errors:
3802d5ac70f0Sopenharmony_ci * <dl>
3803d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>An id in \a key does not exist.
3804d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is
3805d5ac70f0Sopenharmony_ci *                not a compound node.
3806d5ac70f0Sopenharmony_ci * </dl>
3807d5ac70f0Sopenharmony_ci * Additionally, any errors encountered when parsing the hook
3808d5ac70f0Sopenharmony_ci * definitions or returned by the hook functions.
3809d5ac70f0Sopenharmony_ci */
3810d5ac70f0Sopenharmony_ciint snd_config_search_hooks(snd_config_t *config, const char *key, snd_config_t **result)
3811d5ac70f0Sopenharmony_ci{
3812d5ac70f0Sopenharmony_ci	SND_CONFIG_SEARCH(config, key, result, \
3813d5ac70f0Sopenharmony_ci					err = snd_config_hooks(config, NULL); \
3814d5ac70f0Sopenharmony_ci					if (err < 0) \
3815d5ac70f0Sopenharmony_ci						return err; \
3816d5ac70f0Sopenharmony_ci			 );
3817d5ac70f0Sopenharmony_ci}
3818d5ac70f0Sopenharmony_ci
3819d5ac70f0Sopenharmony_ci/**
3820d5ac70f0Sopenharmony_ci * \brief Searches for a node in a configuration tree, expanding aliases and hooks.
3821d5ac70f0Sopenharmony_ci * \param[in] root Handle to the root configuration node containing
3822d5ac70f0Sopenharmony_ci *                 alias definitions.
3823d5ac70f0Sopenharmony_ci * \param[in,out] config Handle to the root of the configuration
3824d5ac70f0Sopenharmony_ci *                       (sub)tree to search.
3825d5ac70f0Sopenharmony_ci * \param[in] key Search key: one or more node keys, separated with dots.
3826d5ac70f0Sopenharmony_ci * \param[out] result The function puts the handle to the node found at
3827d5ac70f0Sopenharmony_ci *                    the address specified by \a result.
3828d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
3829d5ac70f0Sopenharmony_ci *
3830d5ac70f0Sopenharmony_ci * This function searches for a child node of \a config, allowing
3831d5ac70f0Sopenharmony_ci * aliases, like #snd_config_searcha, and expanding hooks, like
3832d5ac70f0Sopenharmony_ci * #snd_config_search_hooks.
3833d5ac70f0Sopenharmony_ci *
3834d5ac70f0Sopenharmony_ci * \par Errors:
3835d5ac70f0Sopenharmony_ci * <dl>
3836d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>An id in \a key or an alias id does not exist.
3837d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is
3838d5ac70f0Sopenharmony_ci *                not a compound node.
3839d5ac70f0Sopenharmony_ci * </dl>
3840d5ac70f0Sopenharmony_ci * Additionally, any errors encountered when parsing the hook
3841d5ac70f0Sopenharmony_ci * definitions or returned by the hook functions.
3842d5ac70f0Sopenharmony_ci */
3843d5ac70f0Sopenharmony_ciint snd_config_searcha_hooks(snd_config_t *root, snd_config_t *config, const char *key, snd_config_t **result)
3844d5ac70f0Sopenharmony_ci{
3845d5ac70f0Sopenharmony_ci	SND_CONFIG_SEARCHA(root, config, key, result,
3846d5ac70f0Sopenharmony_ci					snd_config_searcha_hooks,
3847d5ac70f0Sopenharmony_ci					err = snd_config_hooks(config, NULL); \
3848d5ac70f0Sopenharmony_ci					if (err < 0) \
3849d5ac70f0Sopenharmony_ci						return err; \
3850d5ac70f0Sopenharmony_ci			 );
3851d5ac70f0Sopenharmony_ci}
3852d5ac70f0Sopenharmony_ci
3853d5ac70f0Sopenharmony_ci/**
3854d5ac70f0Sopenharmony_ci * \brief Searches for a node in a configuration tree, expanding aliases and hooks.
3855d5ac70f0Sopenharmony_ci * \param[in] root Handle to the root configuration node containing
3856d5ac70f0Sopenharmony_ci *                 alias definitions.
3857d5ac70f0Sopenharmony_ci * \param[in,out] config Handle to the root of the configuration
3858d5ac70f0Sopenharmony_ci *                       (sub)tree to search.
3859d5ac70f0Sopenharmony_ci * \param[out] result The function puts the handle to the node found at
3860d5ac70f0Sopenharmony_ci *                    the address specified by \a result.
3861d5ac70f0Sopenharmony_ci * \param[in] ... One or more concatenated dot separated search keys,
3862d5ac70f0Sopenharmony_ci *                terminated with \c NULL.
3863d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
3864d5ac70f0Sopenharmony_ci *
3865d5ac70f0Sopenharmony_ci * This function searches for a child node of \a config, allowing
3866d5ac70f0Sopenharmony_ci * aliases and expanding hooks like #snd_config_searcha_hooks, but the
3867d5ac70f0Sopenharmony_ci * search key is the concatenation of all passed seach key strings, like
3868d5ac70f0Sopenharmony_ci * with #snd_config_searchv.
3869d5ac70f0Sopenharmony_ci *
3870d5ac70f0Sopenharmony_ci * \par Errors:
3871d5ac70f0Sopenharmony_ci * <dl>
3872d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>An id in \a key or an alias id does not exist.
3873d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is
3874d5ac70f0Sopenharmony_ci *                not a compound node.
3875d5ac70f0Sopenharmony_ci * </dl>
3876d5ac70f0Sopenharmony_ci * Additionally, any errors encountered when parsing the hook
3877d5ac70f0Sopenharmony_ci * definitions or returned by the hook functions.
3878d5ac70f0Sopenharmony_ci */
3879d5ac70f0Sopenharmony_ciint snd_config_searchva_hooks(snd_config_t *root, snd_config_t *config,
3880d5ac70f0Sopenharmony_ci			      snd_config_t **result, ...)
3881d5ac70f0Sopenharmony_ci{
3882d5ac70f0Sopenharmony_ci	SND_CONFIG_SEARCHVA(root, config, result, snd_config_searcha_hooks);
3883d5ac70f0Sopenharmony_ci}
3884d5ac70f0Sopenharmony_ci
3885d5ac70f0Sopenharmony_ci/**
3886d5ac70f0Sopenharmony_ci * \brief Searches for a node in a configuration tree, using an alias and expanding hooks.
3887d5ac70f0Sopenharmony_ci * \param[in] config Handle to the root of the configuration (sub)tree
3888d5ac70f0Sopenharmony_ci *                   to search.
3889d5ac70f0Sopenharmony_ci * \param[in] base Search key base, or \c NULL.
3890d5ac70f0Sopenharmony_ci * \param[in] key Search key suffix.
3891d5ac70f0Sopenharmony_ci * \param[out] result The function puts the handle to the node found at
3892d5ac70f0Sopenharmony_ci *                    the address specified by \a result.
3893d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
3894d5ac70f0Sopenharmony_ci *
3895d5ac70f0Sopenharmony_ci * This functions searches for a child node of \a config, allowing
3896d5ac70f0Sopenharmony_ci * aliases, like #snd_config_search_alias, and expanding hooks, like
3897d5ac70f0Sopenharmony_ci * #snd_config_search_hooks.
3898d5ac70f0Sopenharmony_ci *
3899d5ac70f0Sopenharmony_ci * \par Errors:
3900d5ac70f0Sopenharmony_ci * <dl>
3901d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>An id in \a key or an alias id does not exist.
3902d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is
3903d5ac70f0Sopenharmony_ci *                not a compound node.
3904d5ac70f0Sopenharmony_ci * </dl>
3905d5ac70f0Sopenharmony_ci * Additionally, any errors encountered when parsing the hook
3906d5ac70f0Sopenharmony_ci * definitions or returned by the hook functions.
3907d5ac70f0Sopenharmony_ci */
3908d5ac70f0Sopenharmony_ciint snd_config_search_alias_hooks(snd_config_t *config,
3909d5ac70f0Sopenharmony_ci				  const char *base, const char *key,
3910d5ac70f0Sopenharmony_ci				  snd_config_t **result)
3911d5ac70f0Sopenharmony_ci{
3912d5ac70f0Sopenharmony_ci	SND_CONFIG_SEARCH_ALIAS(config, base, key, result,
3913d5ac70f0Sopenharmony_ci				snd_config_searcha_hooks,
3914d5ac70f0Sopenharmony_ci				snd_config_searchva_hooks);
3915d5ac70f0Sopenharmony_ci}
3916d5ac70f0Sopenharmony_ci
3917d5ac70f0Sopenharmony_ci/** The name of the environment variable containing the files list for #snd_config_update. */
3918d5ac70f0Sopenharmony_ci#define ALSA_CONFIG_PATH_VAR "ALSA_CONFIG_PATH"
3919d5ac70f0Sopenharmony_ci
3920d5ac70f0Sopenharmony_ci/**
3921d5ac70f0Sopenharmony_ci * \brief Configuration top-level node (the global configuration).
3922d5ac70f0Sopenharmony_ci *
3923d5ac70f0Sopenharmony_ci * This variable contains a handle to the top-level configuration node,
3924d5ac70f0Sopenharmony_ci * as loaded from global configuration file.
3925d5ac70f0Sopenharmony_ci *
3926d5ac70f0Sopenharmony_ci * This variable is initialized or updated by #snd_config_update.
3927d5ac70f0Sopenharmony_ci * Functions like #snd_pcm_open (that use a device name from the global
3928d5ac70f0Sopenharmony_ci * configuration) automatically call #snd_config_update.  Before the
3929d5ac70f0Sopenharmony_ci * first call to #snd_config_update, this variable is \c NULL.
3930d5ac70f0Sopenharmony_ci *
3931d5ac70f0Sopenharmony_ci * The global configuration files are specified in the environment
3932d5ac70f0Sopenharmony_ci * variable \c ALSA_CONFIG_PATH.  If this is not set, the default value
3933d5ac70f0Sopenharmony_ci * is "/usr/share/alsa/alsa.conf".
3934d5ac70f0Sopenharmony_ci *
3935d5ac70f0Sopenharmony_ci * \warning Whenever the configuration tree is updated, all string
3936d5ac70f0Sopenharmony_ci * pointers and configuration node handles previously obtained from this
3937d5ac70f0Sopenharmony_ci * variable may become invalid.
3938d5ac70f0Sopenharmony_ci *
3939d5ac70f0Sopenharmony_ci * \par Conforming to:
3940d5ac70f0Sopenharmony_ci * LSB 3.2
3941d5ac70f0Sopenharmony_ci */
3942d5ac70f0Sopenharmony_cisnd_config_t *snd_config = NULL;
3943d5ac70f0Sopenharmony_ci
3944d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN
3945d5ac70f0Sopenharmony_cistruct finfo {
3946d5ac70f0Sopenharmony_ci	char *name;
3947d5ac70f0Sopenharmony_ci	dev_t dev;
3948d5ac70f0Sopenharmony_ci	ino64_t ino;
3949d5ac70f0Sopenharmony_ci	time_t mtime;
3950d5ac70f0Sopenharmony_ci};
3951d5ac70f0Sopenharmony_ci
3952d5ac70f0Sopenharmony_cistruct _snd_config_update {
3953d5ac70f0Sopenharmony_ci	unsigned int count;
3954d5ac70f0Sopenharmony_ci	struct finfo *finfo;
3955d5ac70f0Sopenharmony_ci};
3956d5ac70f0Sopenharmony_ci#endif /* DOC_HIDDEN */
3957d5ac70f0Sopenharmony_ci
3958d5ac70f0Sopenharmony_cistatic snd_config_update_t *snd_config_global_update = NULL;
3959d5ac70f0Sopenharmony_ci
3960d5ac70f0Sopenharmony_cistatic int snd_config_hooks_call(snd_config_t *root, snd_config_t *config, snd_config_t *private_data)
3961d5ac70f0Sopenharmony_ci{
3962d5ac70f0Sopenharmony_ci	void *h = NULL;
3963d5ac70f0Sopenharmony_ci	snd_config_t *c, *func_conf = NULL;
3964d5ac70f0Sopenharmony_ci	char *buf = NULL, errbuf[256];
3965d5ac70f0Sopenharmony_ci	const char *lib = NULL, *func_name = NULL;
3966d5ac70f0Sopenharmony_ci	const char *str;
3967d5ac70f0Sopenharmony_ci	int (*func)(snd_config_t *root, snd_config_t *config, snd_config_t **dst, snd_config_t *private_data) = NULL;
3968d5ac70f0Sopenharmony_ci	int err;
3969d5ac70f0Sopenharmony_ci
3970d5ac70f0Sopenharmony_ci	err = snd_config_search(config, "func", &c);
3971d5ac70f0Sopenharmony_ci	if (err < 0) {
3972d5ac70f0Sopenharmony_ci		SNDERR("Field func is missing");
3973d5ac70f0Sopenharmony_ci		return err;
3974d5ac70f0Sopenharmony_ci	}
3975d5ac70f0Sopenharmony_ci	err = snd_config_get_string(c, &str);
3976d5ac70f0Sopenharmony_ci	if (err < 0) {
3977d5ac70f0Sopenharmony_ci		SNDERR("Invalid type for field func");
3978d5ac70f0Sopenharmony_ci		return err;
3979d5ac70f0Sopenharmony_ci	}
3980d5ac70f0Sopenharmony_ci	assert(str);
3981d5ac70f0Sopenharmony_ci	err = snd_config_search_definition(root, "hook_func", str, &func_conf);
3982d5ac70f0Sopenharmony_ci	if (err >= 0) {
3983d5ac70f0Sopenharmony_ci		snd_config_iterator_t i, next;
3984d5ac70f0Sopenharmony_ci		if (snd_config_get_type(func_conf) != SND_CONFIG_TYPE_COMPOUND) {
3985d5ac70f0Sopenharmony_ci			SNDERR("Invalid type for func %s definition", str);
3986d5ac70f0Sopenharmony_ci			err = -EINVAL;
3987d5ac70f0Sopenharmony_ci			goto _err;
3988d5ac70f0Sopenharmony_ci		}
3989d5ac70f0Sopenharmony_ci		snd_config_for_each(i, next, func_conf) {
3990d5ac70f0Sopenharmony_ci			snd_config_t *n = snd_config_iterator_entry(i);
3991d5ac70f0Sopenharmony_ci			const char *id = n->id;
3992d5ac70f0Sopenharmony_ci			if (strcmp(id, "comment") == 0)
3993d5ac70f0Sopenharmony_ci				continue;
3994d5ac70f0Sopenharmony_ci			if (strcmp(id, "lib") == 0) {
3995d5ac70f0Sopenharmony_ci				err = snd_config_get_string(n, &lib);
3996d5ac70f0Sopenharmony_ci				if (err < 0) {
3997d5ac70f0Sopenharmony_ci					SNDERR("Invalid type for %s", id);
3998d5ac70f0Sopenharmony_ci					goto _err;
3999d5ac70f0Sopenharmony_ci				}
4000d5ac70f0Sopenharmony_ci				continue;
4001d5ac70f0Sopenharmony_ci			}
4002d5ac70f0Sopenharmony_ci			if (strcmp(id, "func") == 0) {
4003d5ac70f0Sopenharmony_ci				err = snd_config_get_string(n, &func_name);
4004d5ac70f0Sopenharmony_ci				if (err < 0) {
4005d5ac70f0Sopenharmony_ci					SNDERR("Invalid type for %s", id);
4006d5ac70f0Sopenharmony_ci					goto _err;
4007d5ac70f0Sopenharmony_ci				}
4008d5ac70f0Sopenharmony_ci				continue;
4009d5ac70f0Sopenharmony_ci			}
4010d5ac70f0Sopenharmony_ci			SNDERR("Unknown field %s", id);
4011d5ac70f0Sopenharmony_ci		}
4012d5ac70f0Sopenharmony_ci	}
4013d5ac70f0Sopenharmony_ci	if (!func_name) {
4014d5ac70f0Sopenharmony_ci		int len = 16 + strlen(str) + 1;
4015d5ac70f0Sopenharmony_ci		buf = malloc(len);
4016d5ac70f0Sopenharmony_ci		if (! buf) {
4017d5ac70f0Sopenharmony_ci			err = -ENOMEM;
4018d5ac70f0Sopenharmony_ci			goto _err;
4019d5ac70f0Sopenharmony_ci		}
4020d5ac70f0Sopenharmony_ci		snprintf(buf, len, "snd_config_hook_%s", str);
4021d5ac70f0Sopenharmony_ci		buf[len-1] = '\0';
4022d5ac70f0Sopenharmony_ci		func_name = buf;
4023d5ac70f0Sopenharmony_ci	}
4024d5ac70f0Sopenharmony_ci	h = INTERNAL(snd_dlopen)(lib, RTLD_NOW, errbuf, sizeof(errbuf));
4025d5ac70f0Sopenharmony_ci	func = h ? snd_dlsym(h, func_name, SND_DLSYM_VERSION(SND_CONFIG_DLSYM_VERSION_HOOK)) : NULL;
4026d5ac70f0Sopenharmony_ci	err = 0;
4027d5ac70f0Sopenharmony_ci	if (!h) {
4028d5ac70f0Sopenharmony_ci		SNDERR("Cannot open shared library %s (%s)", lib, errbuf);
4029d5ac70f0Sopenharmony_ci		err = -ENOENT;
4030d5ac70f0Sopenharmony_ci	} else if (!func) {
4031d5ac70f0Sopenharmony_ci		SNDERR("symbol %s is not defined inside %s", func_name, lib);
4032d5ac70f0Sopenharmony_ci		snd_dlclose(h);
4033d5ac70f0Sopenharmony_ci		err = -ENXIO;
4034d5ac70f0Sopenharmony_ci	}
4035d5ac70f0Sopenharmony_ci	_err:
4036d5ac70f0Sopenharmony_ci	if (func_conf)
4037d5ac70f0Sopenharmony_ci		snd_config_delete(func_conf);
4038d5ac70f0Sopenharmony_ci	if (err >= 0) {
4039d5ac70f0Sopenharmony_ci		snd_config_t *nroot;
4040d5ac70f0Sopenharmony_ci		err = func(root, config, &nroot, private_data);
4041d5ac70f0Sopenharmony_ci		if (err < 0)
4042d5ac70f0Sopenharmony_ci			SNDERR("function %s returned error: %s", func_name, snd_strerror(err));
4043d5ac70f0Sopenharmony_ci		snd_dlclose(h);
4044d5ac70f0Sopenharmony_ci		if (err >= 0 && nroot)
4045d5ac70f0Sopenharmony_ci			err = snd_config_substitute(root, nroot);
4046d5ac70f0Sopenharmony_ci	}
4047d5ac70f0Sopenharmony_ci	free(buf);
4048d5ac70f0Sopenharmony_ci	if (err < 0)
4049d5ac70f0Sopenharmony_ci		return err;
4050d5ac70f0Sopenharmony_ci	return 0;
4051d5ac70f0Sopenharmony_ci}
4052d5ac70f0Sopenharmony_ci
4053d5ac70f0Sopenharmony_cistatic int snd_config_hooks(snd_config_t *config, snd_config_t *private_data)
4054d5ac70f0Sopenharmony_ci{
4055d5ac70f0Sopenharmony_ci	snd_config_t *n;
4056d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
4057d5ac70f0Sopenharmony_ci	int err, hit, idx = 0;
4058d5ac70f0Sopenharmony_ci
4059d5ac70f0Sopenharmony_ci	if ((err = snd_config_search(config, "@hooks", &n)) < 0)
4060d5ac70f0Sopenharmony_ci		return 0;
4061d5ac70f0Sopenharmony_ci	snd_config_lock();
4062d5ac70f0Sopenharmony_ci	snd_config_remove(n);
4063d5ac70f0Sopenharmony_ci	do {
4064d5ac70f0Sopenharmony_ci		hit = 0;
4065d5ac70f0Sopenharmony_ci		snd_config_for_each(i, next, n) {
4066d5ac70f0Sopenharmony_ci			snd_config_t *n = snd_config_iterator_entry(i);
4067d5ac70f0Sopenharmony_ci			const char *id = n->id;
4068d5ac70f0Sopenharmony_ci			long i;
4069d5ac70f0Sopenharmony_ci			err = safe_strtol(id, &i);
4070d5ac70f0Sopenharmony_ci			if (err < 0) {
4071d5ac70f0Sopenharmony_ci				SNDERR("id of field %s is not and integer", id);
4072d5ac70f0Sopenharmony_ci				err = -EINVAL;
4073d5ac70f0Sopenharmony_ci				goto _err;
4074d5ac70f0Sopenharmony_ci			}
4075d5ac70f0Sopenharmony_ci			if (i == idx) {
4076d5ac70f0Sopenharmony_ci				err = snd_config_hooks_call(config, n, private_data);
4077d5ac70f0Sopenharmony_ci				if (err < 0)
4078d5ac70f0Sopenharmony_ci					goto _err;
4079d5ac70f0Sopenharmony_ci				idx++;
4080d5ac70f0Sopenharmony_ci				hit = 1;
4081d5ac70f0Sopenharmony_ci			}
4082d5ac70f0Sopenharmony_ci		}
4083d5ac70f0Sopenharmony_ci	} while (hit);
4084d5ac70f0Sopenharmony_ci	err = 0;
4085d5ac70f0Sopenharmony_ci       _err:
4086d5ac70f0Sopenharmony_ci	snd_config_delete(n);
4087d5ac70f0Sopenharmony_ci	snd_config_unlock();
4088d5ac70f0Sopenharmony_ci	return err;
4089d5ac70f0Sopenharmony_ci}
4090d5ac70f0Sopenharmony_ci
4091d5ac70f0Sopenharmony_cistatic int config_filename_filter(const struct dirent64 *dirent)
4092d5ac70f0Sopenharmony_ci{
4093d5ac70f0Sopenharmony_ci	size_t flen;
4094d5ac70f0Sopenharmony_ci
4095d5ac70f0Sopenharmony_ci	if (dirent == NULL)
4096d5ac70f0Sopenharmony_ci		return 0;
4097d5ac70f0Sopenharmony_ci	if (dirent->d_type == DT_DIR)
4098d5ac70f0Sopenharmony_ci		return 0;
4099d5ac70f0Sopenharmony_ci
4100d5ac70f0Sopenharmony_ci	flen = strlen(dirent->d_name);
4101d5ac70f0Sopenharmony_ci	if (flen <= 5)
4102d5ac70f0Sopenharmony_ci		return 0;
4103d5ac70f0Sopenharmony_ci
4104d5ac70f0Sopenharmony_ci	if (strncmp(&dirent->d_name[flen-5], ".conf", 5) == 0)
4105d5ac70f0Sopenharmony_ci		return 1;
4106d5ac70f0Sopenharmony_ci
4107d5ac70f0Sopenharmony_ci	return 0;
4108d5ac70f0Sopenharmony_ci}
4109d5ac70f0Sopenharmony_ci
4110d5ac70f0Sopenharmony_cistatic int config_file_open(snd_config_t *root, const char *filename)
4111d5ac70f0Sopenharmony_ci{
4112d5ac70f0Sopenharmony_ci	snd_input_t *in;
4113d5ac70f0Sopenharmony_ci	int err;
4114d5ac70f0Sopenharmony_ci
4115d5ac70f0Sopenharmony_ci	err = snd_input_stdio_open(&in, filename, "r");
4116d5ac70f0Sopenharmony_ci	if (err >= 0) {
4117d5ac70f0Sopenharmony_ci		err = snd_config_load(root, in);
4118d5ac70f0Sopenharmony_ci		snd_input_close(in);
4119d5ac70f0Sopenharmony_ci		if (err < 0)
4120d5ac70f0Sopenharmony_ci			SNDERR("%s may be old or corrupted: consider to remove or fix it", filename);
4121d5ac70f0Sopenharmony_ci	} else
4122d5ac70f0Sopenharmony_ci		SNDERR("cannot access file %s", filename);
4123d5ac70f0Sopenharmony_ci
4124d5ac70f0Sopenharmony_ci	return err;
4125d5ac70f0Sopenharmony_ci}
4126d5ac70f0Sopenharmony_ci
4127d5ac70f0Sopenharmony_cistatic int config_file_load(snd_config_t *root, const char *fn, int errors)
4128d5ac70f0Sopenharmony_ci{
4129d5ac70f0Sopenharmony_ci	struct stat64 st;
4130d5ac70f0Sopenharmony_ci	struct dirent64 **namelist;
4131d5ac70f0Sopenharmony_ci	int err, n;
4132d5ac70f0Sopenharmony_ci
4133d5ac70f0Sopenharmony_ci	if (!errors && access(fn, R_OK) < 0)
4134d5ac70f0Sopenharmony_ci		return 1;
4135d5ac70f0Sopenharmony_ci	if (stat64(fn, &st) < 0) {
4136d5ac70f0Sopenharmony_ci		SNDERR("cannot stat file/directory %s", fn);
4137d5ac70f0Sopenharmony_ci		return 1;
4138d5ac70f0Sopenharmony_ci	}
4139d5ac70f0Sopenharmony_ci	if (!S_ISDIR(st.st_mode))
4140d5ac70f0Sopenharmony_ci		return config_file_open(root, fn);
4141d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN
4142d5ac70f0Sopenharmony_ci#if defined(_GNU_SOURCE) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) && !defined(__sun) && !defined(__ANDROID__)
4143d5ac70f0Sopenharmony_ci#define SORTFUNC	versionsort64
4144d5ac70f0Sopenharmony_ci#else
4145d5ac70f0Sopenharmony_ci#define SORTFUNC	alphasort64
4146d5ac70f0Sopenharmony_ci#endif
4147d5ac70f0Sopenharmony_ci#endif
4148d5ac70f0Sopenharmony_ci	n = scandir64(fn, &namelist, config_filename_filter, SORTFUNC);
4149d5ac70f0Sopenharmony_ci	if (n > 0) {
4150d5ac70f0Sopenharmony_ci		int j;
4151d5ac70f0Sopenharmony_ci		err = 0;
4152d5ac70f0Sopenharmony_ci		for (j = 0; j < n; ++j) {
4153d5ac70f0Sopenharmony_ci			if (err >= 0) {
4154d5ac70f0Sopenharmony_ci				int sl = strlen(fn) + strlen(namelist[j]->d_name) + 2;
4155d5ac70f0Sopenharmony_ci				char *filename = malloc(sl);
4156d5ac70f0Sopenharmony_ci				snprintf(filename, sl, "%s/%s", fn, namelist[j]->d_name);
4157d5ac70f0Sopenharmony_ci				filename[sl-1] = '\0';
4158d5ac70f0Sopenharmony_ci
4159d5ac70f0Sopenharmony_ci				err = config_file_open(root, filename);
4160d5ac70f0Sopenharmony_ci				free(filename);
4161d5ac70f0Sopenharmony_ci			}
4162d5ac70f0Sopenharmony_ci			free(namelist[j]);
4163d5ac70f0Sopenharmony_ci		}
4164d5ac70f0Sopenharmony_ci		free(namelist);
4165d5ac70f0Sopenharmony_ci		if (err < 0)
4166d5ac70f0Sopenharmony_ci			return err;
4167d5ac70f0Sopenharmony_ci	}
4168d5ac70f0Sopenharmony_ci	return 0;
4169d5ac70f0Sopenharmony_ci}
4170d5ac70f0Sopenharmony_ci
4171d5ac70f0Sopenharmony_cistatic int config_file_load_user(snd_config_t *root, const char *fn, int errors)
4172d5ac70f0Sopenharmony_ci{
4173d5ac70f0Sopenharmony_ci	char *fn2;
4174d5ac70f0Sopenharmony_ci	int err;
4175d5ac70f0Sopenharmony_ci
4176d5ac70f0Sopenharmony_ci	err = snd_user_file(fn, &fn2);
4177d5ac70f0Sopenharmony_ci	if (err < 0)
4178d5ac70f0Sopenharmony_ci		return config_file_load(root, fn, errors);
4179d5ac70f0Sopenharmony_ci	err = config_file_load(root, fn2, errors);
4180d5ac70f0Sopenharmony_ci	free(fn2);
4181d5ac70f0Sopenharmony_ci	return err;
4182d5ac70f0Sopenharmony_ci}
4183d5ac70f0Sopenharmony_ci
4184d5ac70f0Sopenharmony_cistatic int config_file_load_user_all(snd_config_t *_root, snd_config_t *_file, int errors)
4185d5ac70f0Sopenharmony_ci{
4186d5ac70f0Sopenharmony_ci	snd_config_t *file = _file, *root = _root, *n;
4187d5ac70f0Sopenharmony_ci	char *name, *name2, *remain, *rname = NULL;
4188d5ac70f0Sopenharmony_ci	int err;
4189d5ac70f0Sopenharmony_ci
4190d5ac70f0Sopenharmony_ci	if (snd_config_get_type(_file) == SND_CONFIG_TYPE_COMPOUND) {
4191d5ac70f0Sopenharmony_ci		if ((err = snd_config_search(_file, "file", &file)) < 0) {
4192d5ac70f0Sopenharmony_ci			SNDERR("Field file not found");
4193d5ac70f0Sopenharmony_ci			return err;
4194d5ac70f0Sopenharmony_ci		}
4195d5ac70f0Sopenharmony_ci		if ((err = snd_config_search(_file, "root", &root)) >= 0) {
4196d5ac70f0Sopenharmony_ci			err = snd_config_get_ascii(root, &rname);
4197d5ac70f0Sopenharmony_ci			if (err < 0) {
4198d5ac70f0Sopenharmony_ci				SNDERR("Field root is bad");
4199d5ac70f0Sopenharmony_ci				return err;
4200d5ac70f0Sopenharmony_ci			}
4201d5ac70f0Sopenharmony_ci			err = snd_config_make_compound(&root, rname, 0);
4202d5ac70f0Sopenharmony_ci			if (err < 0)
4203d5ac70f0Sopenharmony_ci				return err;
4204d5ac70f0Sopenharmony_ci		}
4205d5ac70f0Sopenharmony_ci	}
4206d5ac70f0Sopenharmony_ci	if ((err = snd_config_get_ascii(file, &name)) < 0)
4207d5ac70f0Sopenharmony_ci		goto _err;
4208d5ac70f0Sopenharmony_ci	name2 = name;
4209d5ac70f0Sopenharmony_ci	remain = strstr(name, "|||");
4210d5ac70f0Sopenharmony_ci	while (1) {
4211d5ac70f0Sopenharmony_ci		if (remain) {
4212d5ac70f0Sopenharmony_ci			*remain = '\0';
4213d5ac70f0Sopenharmony_ci			remain += 3;
4214d5ac70f0Sopenharmony_ci		}
4215d5ac70f0Sopenharmony_ci		err = config_file_load_user(root, name2, errors);
4216d5ac70f0Sopenharmony_ci		if (err < 0)
4217d5ac70f0Sopenharmony_ci			goto _err;
4218d5ac70f0Sopenharmony_ci		if (err == 0)	/* first hit wins */
4219d5ac70f0Sopenharmony_ci			break;
4220d5ac70f0Sopenharmony_ci		if (!remain)
4221d5ac70f0Sopenharmony_ci			break;
4222d5ac70f0Sopenharmony_ci		name2 = remain;
4223d5ac70f0Sopenharmony_ci		remain = strstr(remain, "|||");
4224d5ac70f0Sopenharmony_ci	}
4225d5ac70f0Sopenharmony_ci_err:
4226d5ac70f0Sopenharmony_ci	if (root != _root) {
4227d5ac70f0Sopenharmony_ci		if (err == 0) {
4228d5ac70f0Sopenharmony_ci			if (snd_config_get_type(root) == SND_CONFIG_TYPE_COMPOUND) {
4229d5ac70f0Sopenharmony_ci				if (snd_config_is_empty(root))
4230d5ac70f0Sopenharmony_ci					goto _del;
4231d5ac70f0Sopenharmony_ci			}
4232d5ac70f0Sopenharmony_ci			err = snd_config_make_path(&n, _root, rname, 0, 1);
4233d5ac70f0Sopenharmony_ci			if (err < 0)
4234d5ac70f0Sopenharmony_ci				goto _del;
4235d5ac70f0Sopenharmony_ci			err = snd_config_substitute(n, root);
4236d5ac70f0Sopenharmony_ci			if (err == 0)
4237d5ac70f0Sopenharmony_ci				goto _fin;
4238d5ac70f0Sopenharmony_ci		}
4239d5ac70f0Sopenharmony_ci_del:
4240d5ac70f0Sopenharmony_ci		snd_config_delete(root);
4241d5ac70f0Sopenharmony_ci	}
4242d5ac70f0Sopenharmony_ci_fin:
4243d5ac70f0Sopenharmony_ci	free(name);
4244d5ac70f0Sopenharmony_ci	free(rname);
4245d5ac70f0Sopenharmony_ci	return err;
4246d5ac70f0Sopenharmony_ci}
4247d5ac70f0Sopenharmony_ci
4248d5ac70f0Sopenharmony_ci/**
4249d5ac70f0Sopenharmony_ci * \brief Loads and parses the given configurations files.
4250d5ac70f0Sopenharmony_ci * \param[in] root Handle to the root configuration node.
4251d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration node for this hook.
4252d5ac70f0Sopenharmony_ci * \param[out] dst The function puts the handle to the configuration
4253d5ac70f0Sopenharmony_ci *                 node loaded from the file(s) at the address specified
4254d5ac70f0Sopenharmony_ci *                 by \a dst.
4255d5ac70f0Sopenharmony_ci * \param[in] private_data Handle to the private data configuration node.
4256d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
4257d5ac70f0Sopenharmony_ci *
4258d5ac70f0Sopenharmony_ci * See \ref confhooks for an example.
4259d5ac70f0Sopenharmony_ci */
4260d5ac70f0Sopenharmony_ciint snd_config_hook_load(snd_config_t *root, snd_config_t *config, snd_config_t **dst, snd_config_t *private_data)
4261d5ac70f0Sopenharmony_ci{
4262d5ac70f0Sopenharmony_ci	snd_config_t *n;
4263d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
4264d5ac70f0Sopenharmony_ci	int err, idx = 0, errors = 1, hit;
4265d5ac70f0Sopenharmony_ci
4266d5ac70f0Sopenharmony_ci	assert(root && dst);
4267d5ac70f0Sopenharmony_ci	if ((err = snd_config_search(config, "errors", &n)) >= 0) {
4268d5ac70f0Sopenharmony_ci		errors = snd_config_get_bool(n);
4269d5ac70f0Sopenharmony_ci		if (errors < 0) {
4270d5ac70f0Sopenharmony_ci			SNDERR("Invalid bool value in field errors");
4271d5ac70f0Sopenharmony_ci			return errors;
4272d5ac70f0Sopenharmony_ci		}
4273d5ac70f0Sopenharmony_ci	}
4274d5ac70f0Sopenharmony_ci	if ((err = snd_config_search(config, "files", &n)) < 0) {
4275d5ac70f0Sopenharmony_ci		SNDERR("Unable to find field files in the pre-load section");
4276d5ac70f0Sopenharmony_ci		return -EINVAL;
4277d5ac70f0Sopenharmony_ci	}
4278d5ac70f0Sopenharmony_ci	if ((err = snd_config_expand(n, root, NULL, private_data, &n)) < 0) {
4279d5ac70f0Sopenharmony_ci		SNDERR("Unable to expand filenames in the pre-load section");
4280d5ac70f0Sopenharmony_ci		return err;
4281d5ac70f0Sopenharmony_ci	}
4282d5ac70f0Sopenharmony_ci	if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
4283d5ac70f0Sopenharmony_ci		SNDERR("Invalid type for field filenames");
4284d5ac70f0Sopenharmony_ci		goto _err;
4285d5ac70f0Sopenharmony_ci	}
4286d5ac70f0Sopenharmony_ci	do {
4287d5ac70f0Sopenharmony_ci		hit = 0;
4288d5ac70f0Sopenharmony_ci		snd_config_for_each(i, next, n) {
4289d5ac70f0Sopenharmony_ci			snd_config_t *n = snd_config_iterator_entry(i);
4290d5ac70f0Sopenharmony_ci			const char *id = n->id;
4291d5ac70f0Sopenharmony_ci			long i;
4292d5ac70f0Sopenharmony_ci			err = safe_strtol(id, &i);
4293d5ac70f0Sopenharmony_ci			if (err < 0) {
4294d5ac70f0Sopenharmony_ci				SNDERR("id of field %s is not and integer", id);
4295d5ac70f0Sopenharmony_ci				err = -EINVAL;
4296d5ac70f0Sopenharmony_ci				goto _err;
4297d5ac70f0Sopenharmony_ci			}
4298d5ac70f0Sopenharmony_ci			if (i == idx) {
4299d5ac70f0Sopenharmony_ci				err = config_file_load_user_all(root, n, errors);
4300d5ac70f0Sopenharmony_ci				if (err < 0)
4301d5ac70f0Sopenharmony_ci					goto _err;
4302d5ac70f0Sopenharmony_ci				idx++;
4303d5ac70f0Sopenharmony_ci				hit = 1;
4304d5ac70f0Sopenharmony_ci			}
4305d5ac70f0Sopenharmony_ci		}
4306d5ac70f0Sopenharmony_ci	} while (hit);
4307d5ac70f0Sopenharmony_ci	*dst = NULL;
4308d5ac70f0Sopenharmony_ci	err = 0;
4309d5ac70f0Sopenharmony_ci       _err:
4310d5ac70f0Sopenharmony_ci	snd_config_delete(n);
4311d5ac70f0Sopenharmony_ci	return err;
4312d5ac70f0Sopenharmony_ci}
4313d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN
4314d5ac70f0Sopenharmony_ciSND_DLSYM_BUILD_VERSION(snd_config_hook_load, SND_CONFIG_DLSYM_VERSION_HOOK);
4315d5ac70f0Sopenharmony_ci#endif
4316d5ac70f0Sopenharmony_ci
4317d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN
4318d5ac70f0Sopenharmony_ciint snd_determine_driver(int card, char **driver);
4319d5ac70f0Sopenharmony_ci#endif
4320d5ac70f0Sopenharmony_ci
4321d5ac70f0Sopenharmony_cistatic snd_config_t *_snd_config_hook_private_data(int card, const char *driver)
4322d5ac70f0Sopenharmony_ci{
4323d5ac70f0Sopenharmony_ci	snd_config_t *private_data, *v;
4324d5ac70f0Sopenharmony_ci	int err;
4325d5ac70f0Sopenharmony_ci
4326d5ac70f0Sopenharmony_ci	err = snd_config_make_compound(&private_data, NULL, 0);
4327d5ac70f0Sopenharmony_ci	if (err < 0)
4328d5ac70f0Sopenharmony_ci		goto __err;
4329d5ac70f0Sopenharmony_ci	err = snd_config_imake_integer(&v, "integer", card);
4330d5ac70f0Sopenharmony_ci	if (err < 0)
4331d5ac70f0Sopenharmony_ci		goto __err;
4332d5ac70f0Sopenharmony_ci	err = snd_config_add(private_data, v);
4333d5ac70f0Sopenharmony_ci	if (err < 0) {
4334d5ac70f0Sopenharmony_ci		snd_config_delete(v);
4335d5ac70f0Sopenharmony_ci		goto __err;
4336d5ac70f0Sopenharmony_ci	}
4337d5ac70f0Sopenharmony_ci	err = snd_config_imake_string(&v, "string", driver);
4338d5ac70f0Sopenharmony_ci	if (err < 0)
4339d5ac70f0Sopenharmony_ci		goto __err;
4340d5ac70f0Sopenharmony_ci	err = snd_config_add(private_data, v);
4341d5ac70f0Sopenharmony_ci	if (err < 0) {
4342d5ac70f0Sopenharmony_ci		snd_config_delete(v);
4343d5ac70f0Sopenharmony_ci		goto __err;
4344d5ac70f0Sopenharmony_ci	}
4345d5ac70f0Sopenharmony_ci	return private_data;
4346d5ac70f0Sopenharmony_ci
4347d5ac70f0Sopenharmony_ci__err:
4348d5ac70f0Sopenharmony_ci	snd_config_delete(private_data);
4349d5ac70f0Sopenharmony_ci	return NULL;
4350d5ac70f0Sopenharmony_ci}
4351d5ac70f0Sopenharmony_ci
4352d5ac70f0Sopenharmony_cistatic int _snd_config_hook_table(snd_config_t *root, snd_config_t *config, snd_config_t *private_data)
4353d5ac70f0Sopenharmony_ci{
4354d5ac70f0Sopenharmony_ci	snd_config_t *n, *tn;
4355d5ac70f0Sopenharmony_ci	const char *id;
4356d5ac70f0Sopenharmony_ci	int err;
4357d5ac70f0Sopenharmony_ci
4358d5ac70f0Sopenharmony_ci	if (snd_config_search(config, "table", &n) < 0)
4359d5ac70f0Sopenharmony_ci		return 0;
4360d5ac70f0Sopenharmony_ci	if ((err = snd_config_expand(n, root, NULL, private_data, &n)) < 0) {
4361d5ac70f0Sopenharmony_ci		SNDERR("Unable to expand table compound");
4362d5ac70f0Sopenharmony_ci		return err;
4363d5ac70f0Sopenharmony_ci	}
4364d5ac70f0Sopenharmony_ci	if (snd_config_search(n, "id", &tn) < 0 ||
4365d5ac70f0Sopenharmony_ci	    snd_config_get_string(tn, &id) < 0) {
4366d5ac70f0Sopenharmony_ci		SNDERR("Unable to find field table.id");
4367d5ac70f0Sopenharmony_ci		snd_config_delete(n);
4368d5ac70f0Sopenharmony_ci		return -EINVAL;
4369d5ac70f0Sopenharmony_ci	}
4370d5ac70f0Sopenharmony_ci	if (snd_config_search(n, "value", &tn) < 0 ||
4371d5ac70f0Sopenharmony_ci	    snd_config_get_type(tn) != SND_CONFIG_TYPE_STRING) {
4372d5ac70f0Sopenharmony_ci		SNDERR("Unable to find field table.value");
4373d5ac70f0Sopenharmony_ci		snd_config_delete(n);
4374d5ac70f0Sopenharmony_ci		return -EINVAL;
4375d5ac70f0Sopenharmony_ci	}
4376d5ac70f0Sopenharmony_ci	snd_config_remove(tn);
4377d5ac70f0Sopenharmony_ci	if ((err = snd_config_set_id(tn, id)) < 0) {
4378d5ac70f0Sopenharmony_ci		snd_config_delete(tn);
4379d5ac70f0Sopenharmony_ci		snd_config_delete(n);
4380d5ac70f0Sopenharmony_ci		return err;
4381d5ac70f0Sopenharmony_ci	}
4382d5ac70f0Sopenharmony_ci	snd_config_delete(n);
4383d5ac70f0Sopenharmony_ci	if ((err = snd_config_add(root, tn)) < 0) {
4384d5ac70f0Sopenharmony_ci		snd_config_delete(tn);
4385d5ac70f0Sopenharmony_ci		return err;
4386d5ac70f0Sopenharmony_ci	}
4387d5ac70f0Sopenharmony_ci	return 0;
4388d5ac70f0Sopenharmony_ci}
4389d5ac70f0Sopenharmony_ci
4390d5ac70f0Sopenharmony_ci/**
4391d5ac70f0Sopenharmony_ci * \brief Loads and parses the given configurations files for each
4392d5ac70f0Sopenharmony_ci *        installed sound card.
4393d5ac70f0Sopenharmony_ci * \param[in] root Handle to the root configuration node.
4394d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration node for this hook.
4395d5ac70f0Sopenharmony_ci * \param[out] dst The function puts the handle to the configuration
4396d5ac70f0Sopenharmony_ci *                 node loaded from the file(s) at the address specified
4397d5ac70f0Sopenharmony_ci *                 by \a dst.
4398d5ac70f0Sopenharmony_ci * \param[in] private_data Handle to the private data configuration node.
4399d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
4400d5ac70f0Sopenharmony_ci *
4401d5ac70f0Sopenharmony_ci * This function works like #snd_config_hook_load, but the files are
4402d5ac70f0Sopenharmony_ci * loaded once for each sound card.  The driver name is available with
4403d5ac70f0Sopenharmony_ci * the \c private_string function to customize the file name.
4404d5ac70f0Sopenharmony_ci */
4405d5ac70f0Sopenharmony_ciint snd_config_hook_load_for_all_cards(snd_config_t *root, snd_config_t *config, snd_config_t **dst, snd_config_t *private_data ATTRIBUTE_UNUSED)
4406d5ac70f0Sopenharmony_ci{
4407d5ac70f0Sopenharmony_ci	int card = -1, err;
4408d5ac70f0Sopenharmony_ci	snd_config_t *loaded;	// trace loaded cards
4409d5ac70f0Sopenharmony_ci
4410d5ac70f0Sopenharmony_ci	err = snd_config_top(&loaded);
4411d5ac70f0Sopenharmony_ci	if (err < 0)
4412d5ac70f0Sopenharmony_ci		return err;
4413d5ac70f0Sopenharmony_ci	do {
4414d5ac70f0Sopenharmony_ci		err = snd_card_next(&card);
4415d5ac70f0Sopenharmony_ci		if (err < 0)
4416d5ac70f0Sopenharmony_ci			goto __fin_err;
4417d5ac70f0Sopenharmony_ci		if (card >= 0) {
4418d5ac70f0Sopenharmony_ci			snd_config_t *n, *m, *private_data = NULL;
4419d5ac70f0Sopenharmony_ci			const char *driver;
4420d5ac70f0Sopenharmony_ci			char *fdriver = NULL;
4421d5ac70f0Sopenharmony_ci			bool load;
4422d5ac70f0Sopenharmony_ci			err = snd_determine_driver(card, &fdriver);
4423d5ac70f0Sopenharmony_ci			if (err < 0)
4424d5ac70f0Sopenharmony_ci				goto __fin_err;
4425d5ac70f0Sopenharmony_ci			if (snd_config_search(root, fdriver, &n) >= 0) {
4426d5ac70f0Sopenharmony_ci				if (snd_config_get_string(n, &driver) < 0) {
4427d5ac70f0Sopenharmony_ci					if (snd_config_get_type(n) == SND_CONFIG_TYPE_COMPOUND) {
4428d5ac70f0Sopenharmony_ci						snd_config_get_id(n, &driver);
4429d5ac70f0Sopenharmony_ci						goto __std;
4430d5ac70f0Sopenharmony_ci					}
4431d5ac70f0Sopenharmony_ci					goto __err;
4432d5ac70f0Sopenharmony_ci				}
4433d5ac70f0Sopenharmony_ci				while (1) {
4434d5ac70f0Sopenharmony_ci					char *s = strchr(driver, '.');
4435d5ac70f0Sopenharmony_ci					if (s == NULL)
4436d5ac70f0Sopenharmony_ci						break;
4437d5ac70f0Sopenharmony_ci					driver = s + 1;
4438d5ac70f0Sopenharmony_ci				}
4439d5ac70f0Sopenharmony_ci				if (snd_config_search(root, driver, &n) >= 0)
4440d5ac70f0Sopenharmony_ci					goto __err;
4441d5ac70f0Sopenharmony_ci			} else {
4442d5ac70f0Sopenharmony_ci				driver = fdriver;
4443d5ac70f0Sopenharmony_ci			}
4444d5ac70f0Sopenharmony_ci		      __std:
4445d5ac70f0Sopenharmony_ci			load = true;
4446d5ac70f0Sopenharmony_ci			err = snd_config_imake_integer(&m, driver, 1);
4447d5ac70f0Sopenharmony_ci			if (err < 0)
4448d5ac70f0Sopenharmony_ci				goto __err;
4449d5ac70f0Sopenharmony_ci			err = snd_config_add(loaded, m);
4450d5ac70f0Sopenharmony_ci			if (err < 0) {
4451d5ac70f0Sopenharmony_ci				if (err == -EEXIST) {
4452d5ac70f0Sopenharmony_ci					snd_config_delete(m);
4453d5ac70f0Sopenharmony_ci					load = false;
4454d5ac70f0Sopenharmony_ci				} else {
4455d5ac70f0Sopenharmony_ci					goto __err;
4456d5ac70f0Sopenharmony_ci				}
4457d5ac70f0Sopenharmony_ci			}
4458d5ac70f0Sopenharmony_ci			private_data = _snd_config_hook_private_data(card, driver);
4459d5ac70f0Sopenharmony_ci			if (!private_data) {
4460d5ac70f0Sopenharmony_ci				err = -ENOMEM;
4461d5ac70f0Sopenharmony_ci				goto __err;
4462d5ac70f0Sopenharmony_ci			}
4463d5ac70f0Sopenharmony_ci			err = _snd_config_hook_table(root, config, private_data);
4464d5ac70f0Sopenharmony_ci			if (err < 0)
4465d5ac70f0Sopenharmony_ci				goto __err;
4466d5ac70f0Sopenharmony_ci			if (load)
4467d5ac70f0Sopenharmony_ci				err = snd_config_hook_load(root, config, &n, private_data);
4468d5ac70f0Sopenharmony_ci		      __err:
4469d5ac70f0Sopenharmony_ci			if (private_data)
4470d5ac70f0Sopenharmony_ci				snd_config_delete(private_data);
4471d5ac70f0Sopenharmony_ci			free(fdriver);
4472d5ac70f0Sopenharmony_ci			if (err < 0)
4473d5ac70f0Sopenharmony_ci				goto __fin_err;
4474d5ac70f0Sopenharmony_ci		}
4475d5ac70f0Sopenharmony_ci	} while (card >= 0);
4476d5ac70f0Sopenharmony_ci	snd_config_delete(loaded);
4477d5ac70f0Sopenharmony_ci	*dst = NULL;
4478d5ac70f0Sopenharmony_ci	return 0;
4479d5ac70f0Sopenharmony_ci__fin_err:
4480d5ac70f0Sopenharmony_ci	snd_config_delete(loaded);
4481d5ac70f0Sopenharmony_ci	return err;
4482d5ac70f0Sopenharmony_ci}
4483d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN
4484d5ac70f0Sopenharmony_ciSND_DLSYM_BUILD_VERSION(snd_config_hook_load_for_all_cards, SND_CONFIG_DLSYM_VERSION_HOOK);
4485d5ac70f0Sopenharmony_ci#endif
4486d5ac70f0Sopenharmony_ci
4487d5ac70f0Sopenharmony_ci/**
4488d5ac70f0Sopenharmony_ci * \brief Updates a configuration tree by rereading the configuration files (if needed).
4489d5ac70f0Sopenharmony_ci * \param[in,out] _top Address of the handle to the top-level node.
4490d5ac70f0Sopenharmony_ci * \param[in,out] _update Address of a pointer to private update information.
4491d5ac70f0Sopenharmony_ci * \param[in] cfgs A list of configuration file names, delimited with ':'.
4492d5ac70f0Sopenharmony_ci *                 If \p cfgs is \c NULL, the default global
4493d5ac70f0Sopenharmony_ci *                 configuration file is used.
4494d5ac70f0Sopenharmony_ci * \return 0 if \a _top was up to date, 1 if the configuration files
4495d5ac70f0Sopenharmony_ci *         have been reread, otherwise a negative error code.
4496d5ac70f0Sopenharmony_ci *
4497d5ac70f0Sopenharmony_ci * The variables pointed to by \a _top and \a _update can be initialized
4498d5ac70f0Sopenharmony_ci * to \c NULL before the first call to this function.  The private
4499d5ac70f0Sopenharmony_ci * update information holds information about all used configuration
4500d5ac70f0Sopenharmony_ci * files that allows this function to detects changes to them; this data
4501d5ac70f0Sopenharmony_ci * can be freed with #snd_config_update_free.
4502d5ac70f0Sopenharmony_ci *
4503d5ac70f0Sopenharmony_ci * The global configuration files are specified in the environment variable
4504d5ac70f0Sopenharmony_ci * \c ALSA_CONFIG_PATH.
4505d5ac70f0Sopenharmony_ci *
4506d5ac70f0Sopenharmony_ci * \warning If the configuration tree is reread, all string pointers and
4507d5ac70f0Sopenharmony_ci * configuration node handles previously obtained from this tree become
4508d5ac70f0Sopenharmony_ci * invalid.
4509d5ac70f0Sopenharmony_ci *
4510d5ac70f0Sopenharmony_ci * \par Errors:
4511d5ac70f0Sopenharmony_ci * Any errors encountered when parsing the input or returned by hooks or
4512d5ac70f0Sopenharmony_ci * functions.
4513d5ac70f0Sopenharmony_ci */
4514d5ac70f0Sopenharmony_ciint snd_config_update_r(snd_config_t **_top, snd_config_update_t **_update, const char *cfgs)
4515d5ac70f0Sopenharmony_ci{
4516d5ac70f0Sopenharmony_ci	int err;
4517d5ac70f0Sopenharmony_ci	const char *configs, *c;
4518d5ac70f0Sopenharmony_ci	unsigned int k;
4519d5ac70f0Sopenharmony_ci	size_t l;
4520d5ac70f0Sopenharmony_ci	snd_config_update_t *local;
4521d5ac70f0Sopenharmony_ci	snd_config_update_t *update;
4522d5ac70f0Sopenharmony_ci	snd_config_t *top;
4523d5ac70f0Sopenharmony_ci
4524d5ac70f0Sopenharmony_ci	assert(_top && _update);
4525d5ac70f0Sopenharmony_ci	top = *_top;
4526d5ac70f0Sopenharmony_ci	update = *_update;
4527d5ac70f0Sopenharmony_ci	configs = cfgs;
4528d5ac70f0Sopenharmony_ci	if (!configs) {
4529d5ac70f0Sopenharmony_ci		configs = getenv(ALSA_CONFIG_PATH_VAR);
4530d5ac70f0Sopenharmony_ci		if (!configs || !*configs) {
4531d5ac70f0Sopenharmony_ci			const char *topdir = snd_config_topdir();
4532d5ac70f0Sopenharmony_ci			char *s = alloca(strlen(topdir) +
4533d5ac70f0Sopenharmony_ci					 strlen("alsa.conf") + 2);
4534d5ac70f0Sopenharmony_ci			sprintf(s, "%s/alsa.conf", topdir);
4535d5ac70f0Sopenharmony_ci			configs = s;
4536d5ac70f0Sopenharmony_ci		}
4537d5ac70f0Sopenharmony_ci	}
4538d5ac70f0Sopenharmony_ci	for (k = 0, c = configs; (l = strcspn(c, ": ")) > 0; ) {
4539d5ac70f0Sopenharmony_ci		c += l;
4540d5ac70f0Sopenharmony_ci		k++;
4541d5ac70f0Sopenharmony_ci		if (!*c)
4542d5ac70f0Sopenharmony_ci			break;
4543d5ac70f0Sopenharmony_ci		c++;
4544d5ac70f0Sopenharmony_ci	}
4545d5ac70f0Sopenharmony_ci	if (k == 0) {
4546d5ac70f0Sopenharmony_ci		local = NULL;
4547d5ac70f0Sopenharmony_ci		goto _reread;
4548d5ac70f0Sopenharmony_ci	}
4549d5ac70f0Sopenharmony_ci	local = (snd_config_update_t *)calloc(1, sizeof(snd_config_update_t));
4550d5ac70f0Sopenharmony_ci	if (!local)
4551d5ac70f0Sopenharmony_ci		return -ENOMEM;
4552d5ac70f0Sopenharmony_ci	local->count = k;
4553d5ac70f0Sopenharmony_ci	local->finfo = calloc(local->count, sizeof(struct finfo));
4554d5ac70f0Sopenharmony_ci	if (!local->finfo) {
4555d5ac70f0Sopenharmony_ci		free(local);
4556d5ac70f0Sopenharmony_ci		return -ENOMEM;
4557d5ac70f0Sopenharmony_ci	}
4558d5ac70f0Sopenharmony_ci	for (k = 0, c = configs; (l = strcspn(c, ": ")) > 0; ) {
4559d5ac70f0Sopenharmony_ci		char name[l + 1];
4560d5ac70f0Sopenharmony_ci		memcpy(name, c, l);
4561d5ac70f0Sopenharmony_ci		name[l] = 0;
4562d5ac70f0Sopenharmony_ci		err = snd_user_file(name, &local->finfo[k].name);
4563d5ac70f0Sopenharmony_ci		if (err < 0)
4564d5ac70f0Sopenharmony_ci			goto _end;
4565d5ac70f0Sopenharmony_ci		c += l;
4566d5ac70f0Sopenharmony_ci		k++;
4567d5ac70f0Sopenharmony_ci		if (!*c)
4568d5ac70f0Sopenharmony_ci			break;
4569d5ac70f0Sopenharmony_ci		c++;
4570d5ac70f0Sopenharmony_ci	}
4571d5ac70f0Sopenharmony_ci	for (k = 0; k < local->count; ++k) {
4572d5ac70f0Sopenharmony_ci		struct stat64 st;
4573d5ac70f0Sopenharmony_ci		struct finfo *lf = &local->finfo[k];
4574d5ac70f0Sopenharmony_ci		if (stat64(lf->name, &st) >= 0) {
4575d5ac70f0Sopenharmony_ci			lf->dev = st.st_dev;
4576d5ac70f0Sopenharmony_ci			lf->ino = st.st_ino;
4577d5ac70f0Sopenharmony_ci			lf->mtime = st.st_mtime;
4578d5ac70f0Sopenharmony_ci		} else {
4579d5ac70f0Sopenharmony_ci			SNDERR("Cannot access file %s", lf->name);
4580d5ac70f0Sopenharmony_ci			free(lf->name);
4581d5ac70f0Sopenharmony_ci			memmove(&local->finfo[k], &local->finfo[k+1], sizeof(struct finfo) * (local->count - k - 1));
4582d5ac70f0Sopenharmony_ci			k--;
4583d5ac70f0Sopenharmony_ci			local->count--;
4584d5ac70f0Sopenharmony_ci		}
4585d5ac70f0Sopenharmony_ci	}
4586d5ac70f0Sopenharmony_ci	if (!update)
4587d5ac70f0Sopenharmony_ci		goto _reread;
4588d5ac70f0Sopenharmony_ci	if (local->count != update->count)
4589d5ac70f0Sopenharmony_ci		goto _reread;
4590d5ac70f0Sopenharmony_ci	for (k = 0; k < local->count; ++k) {
4591d5ac70f0Sopenharmony_ci		struct finfo *lf = &local->finfo[k];
4592d5ac70f0Sopenharmony_ci		struct finfo *uf = &update->finfo[k];
4593d5ac70f0Sopenharmony_ci		if (strcmp(lf->name, uf->name) != 0 ||
4594d5ac70f0Sopenharmony_ci		    lf->dev != uf->dev ||
4595d5ac70f0Sopenharmony_ci		    lf->ino != uf->ino ||
4596d5ac70f0Sopenharmony_ci		    lf->mtime != uf->mtime)
4597d5ac70f0Sopenharmony_ci			goto _reread;
4598d5ac70f0Sopenharmony_ci	}
4599d5ac70f0Sopenharmony_ci	err = 0;
4600d5ac70f0Sopenharmony_ci
4601d5ac70f0Sopenharmony_ci _end:
4602d5ac70f0Sopenharmony_ci	if (err < 0) {
4603d5ac70f0Sopenharmony_ci		if (top) {
4604d5ac70f0Sopenharmony_ci			snd_config_delete(top);
4605d5ac70f0Sopenharmony_ci			*_top = NULL;
4606d5ac70f0Sopenharmony_ci		}
4607d5ac70f0Sopenharmony_ci		if (update) {
4608d5ac70f0Sopenharmony_ci			snd_config_update_free(update);
4609d5ac70f0Sopenharmony_ci			*_update = NULL;
4610d5ac70f0Sopenharmony_ci		}
4611d5ac70f0Sopenharmony_ci	}
4612d5ac70f0Sopenharmony_ci	if (local)
4613d5ac70f0Sopenharmony_ci		snd_config_update_free(local);
4614d5ac70f0Sopenharmony_ci	return err;
4615d5ac70f0Sopenharmony_ci
4616d5ac70f0Sopenharmony_ci _reread:
4617d5ac70f0Sopenharmony_ci 	*_top = NULL;
4618d5ac70f0Sopenharmony_ci 	*_update = NULL;
4619d5ac70f0Sopenharmony_ci 	if (update) {
4620d5ac70f0Sopenharmony_ci 		snd_config_update_free(update);
4621d5ac70f0Sopenharmony_ci 		update = NULL;
4622d5ac70f0Sopenharmony_ci 	}
4623d5ac70f0Sopenharmony_ci	if (top) {
4624d5ac70f0Sopenharmony_ci		snd_config_delete(top);
4625d5ac70f0Sopenharmony_ci		top = NULL;
4626d5ac70f0Sopenharmony_ci	}
4627d5ac70f0Sopenharmony_ci	err = snd_config_top(&top);
4628d5ac70f0Sopenharmony_ci	if (err < 0)
4629d5ac70f0Sopenharmony_ci		goto _end;
4630d5ac70f0Sopenharmony_ci	if (!local)
4631d5ac70f0Sopenharmony_ci		goto _skip;
4632d5ac70f0Sopenharmony_ci	for (k = 0; k < local->count; ++k) {
4633d5ac70f0Sopenharmony_ci		snd_input_t *in;
4634d5ac70f0Sopenharmony_ci		err = snd_input_stdio_open(&in, local->finfo[k].name, "r");
4635d5ac70f0Sopenharmony_ci		if (err >= 0) {
4636d5ac70f0Sopenharmony_ci			err = snd_config_load(top, in);
4637d5ac70f0Sopenharmony_ci			snd_input_close(in);
4638d5ac70f0Sopenharmony_ci			if (err < 0) {
4639d5ac70f0Sopenharmony_ci				SNDERR("%s may be old or corrupted: consider to remove or fix it", local->finfo[k].name);
4640d5ac70f0Sopenharmony_ci				goto _end;
4641d5ac70f0Sopenharmony_ci			}
4642d5ac70f0Sopenharmony_ci		} else {
4643d5ac70f0Sopenharmony_ci			SNDERR("cannot access file %s", local->finfo[k].name);
4644d5ac70f0Sopenharmony_ci		}
4645d5ac70f0Sopenharmony_ci	}
4646d5ac70f0Sopenharmony_ci _skip:
4647d5ac70f0Sopenharmony_ci	err = snd_config_hooks(top, NULL);
4648d5ac70f0Sopenharmony_ci	if (err < 0) {
4649d5ac70f0Sopenharmony_ci		SNDERR("hooks failed, removing configuration");
4650d5ac70f0Sopenharmony_ci		goto _end;
4651d5ac70f0Sopenharmony_ci	}
4652d5ac70f0Sopenharmony_ci	*_top = top;
4653d5ac70f0Sopenharmony_ci	*_update = local;
4654d5ac70f0Sopenharmony_ci	return 1;
4655d5ac70f0Sopenharmony_ci}
4656d5ac70f0Sopenharmony_ci
4657d5ac70f0Sopenharmony_ci/**
4658d5ac70f0Sopenharmony_ci * \brief Updates #snd_config by rereading the global configuration files (if needed).
4659d5ac70f0Sopenharmony_ci * \return 0 if #snd_config was up to date, 1 if #snd_config was
4660d5ac70f0Sopenharmony_ci *         updated, otherwise a negative error code.
4661d5ac70f0Sopenharmony_ci *
4662d5ac70f0Sopenharmony_ci * \warning Whenever #snd_config is updated, all string pointers and
4663d5ac70f0Sopenharmony_ci * configuration node handles previously obtained from it may become
4664d5ac70f0Sopenharmony_ci * invalid.
4665d5ac70f0Sopenharmony_ci * For safer operations, use #snd_config_update_ref and release the config
4666d5ac70f0Sopenharmony_ci * via #snd_config_unref.
4667d5ac70f0Sopenharmony_ci *
4668d5ac70f0Sopenharmony_ci * \par Errors:
4669d5ac70f0Sopenharmony_ci * Any errors encountered when parsing the input or returned by hooks or
4670d5ac70f0Sopenharmony_ci * functions.
4671d5ac70f0Sopenharmony_ci *
4672d5ac70f0Sopenharmony_ci * \par Conforming to:
4673d5ac70f0Sopenharmony_ci * LSB 3.2
4674d5ac70f0Sopenharmony_ci */
4675d5ac70f0Sopenharmony_ciint snd_config_update(void)
4676d5ac70f0Sopenharmony_ci{
4677d5ac70f0Sopenharmony_ci	int err;
4678d5ac70f0Sopenharmony_ci
4679d5ac70f0Sopenharmony_ci	snd_config_lock();
4680d5ac70f0Sopenharmony_ci	err = snd_config_update_r(&snd_config, &snd_config_global_update, NULL);
4681d5ac70f0Sopenharmony_ci	snd_config_unlock();
4682d5ac70f0Sopenharmony_ci	return err;
4683d5ac70f0Sopenharmony_ci}
4684d5ac70f0Sopenharmony_ci
4685d5ac70f0Sopenharmony_ci/**
4686d5ac70f0Sopenharmony_ci * \brief Updates #snd_config and takes its reference.
4687d5ac70f0Sopenharmony_ci * \return 0 if #snd_config was up to date, 1 if #snd_config was
4688d5ac70f0Sopenharmony_ci *         updated, otherwise a negative error code.
4689d5ac70f0Sopenharmony_ci *
4690d5ac70f0Sopenharmony_ci * Unlike #snd_config_update, this function increases a reference counter
4691d5ac70f0Sopenharmony_ci * so that the obtained tree won't be deleted until unreferenced by
4692d5ac70f0Sopenharmony_ci * #snd_config_unref.
4693d5ac70f0Sopenharmony_ci *
4694d5ac70f0Sopenharmony_ci * This function is supposed to be thread-safe.
4695d5ac70f0Sopenharmony_ci */
4696d5ac70f0Sopenharmony_ciint snd_config_update_ref(snd_config_t **top)
4697d5ac70f0Sopenharmony_ci{
4698d5ac70f0Sopenharmony_ci	int err;
4699d5ac70f0Sopenharmony_ci
4700d5ac70f0Sopenharmony_ci	if (top)
4701d5ac70f0Sopenharmony_ci		*top = NULL;
4702d5ac70f0Sopenharmony_ci	snd_config_lock();
4703d5ac70f0Sopenharmony_ci	err = snd_config_update_r(&snd_config, &snd_config_global_update, NULL);
4704d5ac70f0Sopenharmony_ci	if (err >= 0) {
4705d5ac70f0Sopenharmony_ci		if (snd_config) {
4706d5ac70f0Sopenharmony_ci			if (top) {
4707d5ac70f0Sopenharmony_ci				snd_config->refcount++;
4708d5ac70f0Sopenharmony_ci				*top = snd_config;
4709d5ac70f0Sopenharmony_ci			}
4710d5ac70f0Sopenharmony_ci		} else {
4711d5ac70f0Sopenharmony_ci			err = -ENODEV;
4712d5ac70f0Sopenharmony_ci		}
4713d5ac70f0Sopenharmony_ci	}
4714d5ac70f0Sopenharmony_ci	snd_config_unlock();
4715d5ac70f0Sopenharmony_ci	return err;
4716d5ac70f0Sopenharmony_ci}
4717d5ac70f0Sopenharmony_ci
4718d5ac70f0Sopenharmony_ci/**
4719d5ac70f0Sopenharmony_ci * \brief Take the reference of the config tree.
4720d5ac70f0Sopenharmony_ci *
4721d5ac70f0Sopenharmony_ci * Increases a reference counter of the given config tree.
4722d5ac70f0Sopenharmony_ci *
4723d5ac70f0Sopenharmony_ci * This function is supposed to be thread-safe.
4724d5ac70f0Sopenharmony_ci */
4725d5ac70f0Sopenharmony_civoid snd_config_ref(snd_config_t *cfg)
4726d5ac70f0Sopenharmony_ci{
4727d5ac70f0Sopenharmony_ci	snd_config_lock();
4728d5ac70f0Sopenharmony_ci	if (cfg)
4729d5ac70f0Sopenharmony_ci		cfg->refcount++;
4730d5ac70f0Sopenharmony_ci	snd_config_unlock();
4731d5ac70f0Sopenharmony_ci}
4732d5ac70f0Sopenharmony_ci
4733d5ac70f0Sopenharmony_ci/**
4734d5ac70f0Sopenharmony_ci * \brief Unreference the config tree.
4735d5ac70f0Sopenharmony_ci *
4736d5ac70f0Sopenharmony_ci * Decreases a reference counter of the given config tree, and eventually
4737d5ac70f0Sopenharmony_ci * deletes the tree if all references are gone.  This is the counterpart of
4738d5ac70f0Sopenharmony_ci * #snd_config_unref.
4739d5ac70f0Sopenharmony_ci *
4740d5ac70f0Sopenharmony_ci * Also, the config taken via #snd_config_update_ref must be unreferenced
4741d5ac70f0Sopenharmony_ci * by this function, too.
4742d5ac70f0Sopenharmony_ci *
4743d5ac70f0Sopenharmony_ci * This function is supposed to be thread-safe.
4744d5ac70f0Sopenharmony_ci */
4745d5ac70f0Sopenharmony_civoid snd_config_unref(snd_config_t *cfg)
4746d5ac70f0Sopenharmony_ci{
4747d5ac70f0Sopenharmony_ci	snd_config_lock();
4748d5ac70f0Sopenharmony_ci	if (cfg)
4749d5ac70f0Sopenharmony_ci		snd_config_delete(cfg);
4750d5ac70f0Sopenharmony_ci	snd_config_unlock();
4751d5ac70f0Sopenharmony_ci}
4752d5ac70f0Sopenharmony_ci
4753d5ac70f0Sopenharmony_ci/**
4754d5ac70f0Sopenharmony_ci * \brief Frees a private update structure.
4755d5ac70f0Sopenharmony_ci * \param[in] update The private update structure to free.
4756d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
4757d5ac70f0Sopenharmony_ci */
4758d5ac70f0Sopenharmony_ciint snd_config_update_free(snd_config_update_t *update)
4759d5ac70f0Sopenharmony_ci{
4760d5ac70f0Sopenharmony_ci	unsigned int k;
4761d5ac70f0Sopenharmony_ci
4762d5ac70f0Sopenharmony_ci	assert(update);
4763d5ac70f0Sopenharmony_ci	for (k = 0; k < update->count; k++)
4764d5ac70f0Sopenharmony_ci		free(update->finfo[k].name);
4765d5ac70f0Sopenharmony_ci	free(update->finfo);
4766d5ac70f0Sopenharmony_ci	free(update);
4767d5ac70f0Sopenharmony_ci	return 0;
4768d5ac70f0Sopenharmony_ci}
4769d5ac70f0Sopenharmony_ci
4770d5ac70f0Sopenharmony_ci/**
4771d5ac70f0Sopenharmony_ci * \brief Frees the global configuration tree in #snd_config.
4772d5ac70f0Sopenharmony_ci * \return Zero if successful, otherwise a negative error code.
4773d5ac70f0Sopenharmony_ci *
4774d5ac70f0Sopenharmony_ci * This functions releases all resources of the global configuration
4775d5ac70f0Sopenharmony_ci * tree, and sets #snd_config to \c NULL.
4776d5ac70f0Sopenharmony_ci *
4777d5ac70f0Sopenharmony_ci * \par Conforming to:
4778d5ac70f0Sopenharmony_ci * LSB 3.2
4779d5ac70f0Sopenharmony_ci */
4780d5ac70f0Sopenharmony_ciint snd_config_update_free_global(void)
4781d5ac70f0Sopenharmony_ci{
4782d5ac70f0Sopenharmony_ci	snd_config_lock();
4783d5ac70f0Sopenharmony_ci	if (snd_config)
4784d5ac70f0Sopenharmony_ci		snd_config_delete(snd_config);
4785d5ac70f0Sopenharmony_ci	snd_config = NULL;
4786d5ac70f0Sopenharmony_ci	if (snd_config_global_update)
4787d5ac70f0Sopenharmony_ci		snd_config_update_free(snd_config_global_update);
4788d5ac70f0Sopenharmony_ci	snd_config_global_update = NULL;
4789d5ac70f0Sopenharmony_ci	snd_config_unlock();
4790d5ac70f0Sopenharmony_ci	/* FIXME: better to place this in another place... */
4791d5ac70f0Sopenharmony_ci	snd_dlobj_cache_cleanup();
4792d5ac70f0Sopenharmony_ci
4793d5ac70f0Sopenharmony_ci	return 0;
4794d5ac70f0Sopenharmony_ci}
4795d5ac70f0Sopenharmony_ci
4796d5ac70f0Sopenharmony_ci/**
4797d5ac70f0Sopenharmony_ci * \brief Returns an iterator pointing to a node's first child.
4798d5ac70f0Sopenharmony_ci * \param[in] config Handle to a configuration node.
4799d5ac70f0Sopenharmony_ci * \return An iterator pointing to \a config's first child.
4800d5ac70f0Sopenharmony_ci *
4801d5ac70f0Sopenharmony_ci * \a config must be a compound node.
4802d5ac70f0Sopenharmony_ci *
4803d5ac70f0Sopenharmony_ci * The returned iterator is valid if it is not equal to the return value
4804d5ac70f0Sopenharmony_ci * of #snd_config_iterator_end on \a config.
4805d5ac70f0Sopenharmony_ci *
4806d5ac70f0Sopenharmony_ci * Use #snd_config_iterator_entry to get the handle of the node pointed
4807d5ac70f0Sopenharmony_ci * to.
4808d5ac70f0Sopenharmony_ci *
4809d5ac70f0Sopenharmony_ci * \par Conforming to:
4810d5ac70f0Sopenharmony_ci * LSB 3.2
4811d5ac70f0Sopenharmony_ci */
4812d5ac70f0Sopenharmony_cisnd_config_iterator_t snd_config_iterator_first(const snd_config_t *config)
4813d5ac70f0Sopenharmony_ci{
4814d5ac70f0Sopenharmony_ci	assert(config->type == SND_CONFIG_TYPE_COMPOUND);
4815d5ac70f0Sopenharmony_ci	return config->u.compound.fields.next;
4816d5ac70f0Sopenharmony_ci}
4817d5ac70f0Sopenharmony_ci
4818d5ac70f0Sopenharmony_ci/**
4819d5ac70f0Sopenharmony_ci * \brief Returns an iterator pointing to the next sibling.
4820d5ac70f0Sopenharmony_ci * \param[in] iterator An iterator pointing to a child configuration node.
4821d5ac70f0Sopenharmony_ci * \return An iterator pointing to the next sibling of \a iterator.
4822d5ac70f0Sopenharmony_ci *
4823d5ac70f0Sopenharmony_ci * The returned iterator is valid if it is not equal to the return value
4824d5ac70f0Sopenharmony_ci * of #snd_config_iterator_end on the node's parent.
4825d5ac70f0Sopenharmony_ci *
4826d5ac70f0Sopenharmony_ci * Use #snd_config_iterator_entry to get the handle of the node pointed
4827d5ac70f0Sopenharmony_ci * to.
4828d5ac70f0Sopenharmony_ci *
4829d5ac70f0Sopenharmony_ci * \par Conforming to:
4830d5ac70f0Sopenharmony_ci * LSB 3.2
4831d5ac70f0Sopenharmony_ci */
4832d5ac70f0Sopenharmony_cisnd_config_iterator_t snd_config_iterator_next(const snd_config_iterator_t iterator)
4833d5ac70f0Sopenharmony_ci{
4834d5ac70f0Sopenharmony_ci	return iterator->next;
4835d5ac70f0Sopenharmony_ci}
4836d5ac70f0Sopenharmony_ci
4837d5ac70f0Sopenharmony_ci/**
4838d5ac70f0Sopenharmony_ci * \brief Returns an iterator that ends a node's children list.
4839d5ac70f0Sopenharmony_ci * \param[in] config Handle to a configuration node.
4840d5ac70f0Sopenharmony_ci * \return An iterator that indicates the end of \a config's children list.
4841d5ac70f0Sopenharmony_ci *
4842d5ac70f0Sopenharmony_ci * \a config must be a compound node.
4843d5ac70f0Sopenharmony_ci *
4844d5ac70f0Sopenharmony_ci * The return value can be understood as pointing past the last child of
4845d5ac70f0Sopenharmony_ci * \a config.
4846d5ac70f0Sopenharmony_ci *
4847d5ac70f0Sopenharmony_ci * \par Conforming to:
4848d5ac70f0Sopenharmony_ci * LSB 3.2
4849d5ac70f0Sopenharmony_ci */
4850d5ac70f0Sopenharmony_cisnd_config_iterator_t snd_config_iterator_end(const snd_config_t *config)
4851d5ac70f0Sopenharmony_ci{
4852d5ac70f0Sopenharmony_ci	assert(config->type == SND_CONFIG_TYPE_COMPOUND);
4853d5ac70f0Sopenharmony_ci	return (const snd_config_iterator_t)&config->u.compound.fields;
4854d5ac70f0Sopenharmony_ci}
4855d5ac70f0Sopenharmony_ci
4856d5ac70f0Sopenharmony_ci/**
4857d5ac70f0Sopenharmony_ci * \brief Returns the configuration node handle pointed to by an iterator.
4858d5ac70f0Sopenharmony_ci * \param[in] iterator A configuration node iterator.
4859d5ac70f0Sopenharmony_ci * \return The configuration node handle pointed to by \a iterator.
4860d5ac70f0Sopenharmony_ci *
4861d5ac70f0Sopenharmony_ci * \par Conforming to:
4862d5ac70f0Sopenharmony_ci * LSB 3.2
4863d5ac70f0Sopenharmony_ci */
4864d5ac70f0Sopenharmony_cisnd_config_t *snd_config_iterator_entry(const snd_config_iterator_t iterator)
4865d5ac70f0Sopenharmony_ci{
4866d5ac70f0Sopenharmony_ci	return list_entry(iterator, snd_config_t, list);
4867d5ac70f0Sopenharmony_ci}
4868d5ac70f0Sopenharmony_ci
4869d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN
4870d5ac70f0Sopenharmony_citypedef enum _snd_config_walk_pass {
4871d5ac70f0Sopenharmony_ci	SND_CONFIG_WALK_PASS_PRE,
4872d5ac70f0Sopenharmony_ci	SND_CONFIG_WALK_PASS_POST,
4873d5ac70f0Sopenharmony_ci	SND_CONFIG_WALK_PASS_LEAF,
4874d5ac70f0Sopenharmony_ci} snd_config_walk_pass_t;
4875d5ac70f0Sopenharmony_ci#endif
4876d5ac70f0Sopenharmony_ci
4877d5ac70f0Sopenharmony_ci/* Return 1 if node needs to be attached to parent */
4878d5ac70f0Sopenharmony_ci/* Return 2 if compound is replaced with standard node */
4879d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN
4880d5ac70f0Sopenharmony_citypedef int (*snd_config_walk_callback_t)(snd_config_t *src,
4881d5ac70f0Sopenharmony_ci					  snd_config_t *root,
4882d5ac70f0Sopenharmony_ci					  snd_config_t **dst,
4883d5ac70f0Sopenharmony_ci					  snd_config_walk_pass_t pass,
4884d5ac70f0Sopenharmony_ci					  snd_config_expand_fcn_t fcn,
4885d5ac70f0Sopenharmony_ci					  void *private_data);
4886d5ac70f0Sopenharmony_ci#endif
4887d5ac70f0Sopenharmony_ci
4888d5ac70f0Sopenharmony_cistatic int snd_config_walk(snd_config_t *src,
4889d5ac70f0Sopenharmony_ci			   snd_config_t *root,
4890d5ac70f0Sopenharmony_ci			   snd_config_t **dst,
4891d5ac70f0Sopenharmony_ci			   snd_config_walk_callback_t callback,
4892d5ac70f0Sopenharmony_ci			   snd_config_expand_fcn_t fcn,
4893d5ac70f0Sopenharmony_ci			   void *private_data)
4894d5ac70f0Sopenharmony_ci{
4895d5ac70f0Sopenharmony_ci	int err;
4896d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
4897d5ac70f0Sopenharmony_ci
4898d5ac70f0Sopenharmony_ci	switch (snd_config_get_type(src)) {
4899d5ac70f0Sopenharmony_ci	case SND_CONFIG_TYPE_COMPOUND:
4900d5ac70f0Sopenharmony_ci		err = callback(src, root, dst, SND_CONFIG_WALK_PASS_PRE, fcn, private_data);
4901d5ac70f0Sopenharmony_ci		if (err <= 0)
4902d5ac70f0Sopenharmony_ci			return err;
4903d5ac70f0Sopenharmony_ci		snd_config_for_each(i, next, src) {
4904d5ac70f0Sopenharmony_ci			snd_config_t *s = snd_config_iterator_entry(i);
4905d5ac70f0Sopenharmony_ci			snd_config_t *d = NULL;
4906d5ac70f0Sopenharmony_ci
4907d5ac70f0Sopenharmony_ci			err = snd_config_walk(s, root, (dst && *dst) ? &d : NULL,
4908d5ac70f0Sopenharmony_ci					      callback, fcn, private_data);
4909d5ac70f0Sopenharmony_ci			if (err < 0)
4910d5ac70f0Sopenharmony_ci				goto _error;
4911d5ac70f0Sopenharmony_ci			if (err && d) {
4912d5ac70f0Sopenharmony_ci				err = snd_config_add(*dst, d);
4913d5ac70f0Sopenharmony_ci				if (err < 0)
4914d5ac70f0Sopenharmony_ci					goto _error;
4915d5ac70f0Sopenharmony_ci			}
4916d5ac70f0Sopenharmony_ci		}
4917d5ac70f0Sopenharmony_ci		err = callback(src, root, dst, SND_CONFIG_WALK_PASS_POST, fcn, private_data);
4918d5ac70f0Sopenharmony_ci		if (err <= 0) {
4919d5ac70f0Sopenharmony_ci		_error:
4920d5ac70f0Sopenharmony_ci			if (dst && *dst)
4921d5ac70f0Sopenharmony_ci				snd_config_delete(*dst);
4922d5ac70f0Sopenharmony_ci		}
4923d5ac70f0Sopenharmony_ci		break;
4924d5ac70f0Sopenharmony_ci	default:
4925d5ac70f0Sopenharmony_ci		err = callback(src, root, dst, SND_CONFIG_WALK_PASS_LEAF, fcn, private_data);
4926d5ac70f0Sopenharmony_ci		break;
4927d5ac70f0Sopenharmony_ci	}
4928d5ac70f0Sopenharmony_ci	return err;
4929d5ac70f0Sopenharmony_ci}
4930d5ac70f0Sopenharmony_ci
4931d5ac70f0Sopenharmony_cistatic int _snd_config_copy(snd_config_t *src,
4932d5ac70f0Sopenharmony_ci			    snd_config_t *root ATTRIBUTE_UNUSED,
4933d5ac70f0Sopenharmony_ci			    snd_config_t **dst,
4934d5ac70f0Sopenharmony_ci			    snd_config_walk_pass_t pass,
4935d5ac70f0Sopenharmony_ci			    snd_config_expand_fcn_t fcn ATTRIBUTE_UNUSED,
4936d5ac70f0Sopenharmony_ci			    void *private_data ATTRIBUTE_UNUSED)
4937d5ac70f0Sopenharmony_ci{
4938d5ac70f0Sopenharmony_ci	int err;
4939d5ac70f0Sopenharmony_ci	const char *id = src->id;
4940d5ac70f0Sopenharmony_ci	snd_config_type_t type = snd_config_get_type(src);
4941d5ac70f0Sopenharmony_ci	switch (pass) {
4942d5ac70f0Sopenharmony_ci	case SND_CONFIG_WALK_PASS_PRE:
4943d5ac70f0Sopenharmony_ci		err = snd_config_make_compound(dst, id, src->u.compound.join);
4944d5ac70f0Sopenharmony_ci		if (err < 0)
4945d5ac70f0Sopenharmony_ci			return err;
4946d5ac70f0Sopenharmony_ci		break;
4947d5ac70f0Sopenharmony_ci	case SND_CONFIG_WALK_PASS_LEAF:
4948d5ac70f0Sopenharmony_ci		err = snd_config_make(dst, id, type);
4949d5ac70f0Sopenharmony_ci		if (err < 0)
4950d5ac70f0Sopenharmony_ci			return err;
4951d5ac70f0Sopenharmony_ci		switch (type) {
4952d5ac70f0Sopenharmony_ci		case SND_CONFIG_TYPE_INTEGER:
4953d5ac70f0Sopenharmony_ci		{
4954d5ac70f0Sopenharmony_ci			long v;
4955d5ac70f0Sopenharmony_ci			err = snd_config_get_integer(src, &v);
4956d5ac70f0Sopenharmony_ci			assert(err >= 0);
4957d5ac70f0Sopenharmony_ci			snd_config_set_integer(*dst, v);
4958d5ac70f0Sopenharmony_ci			break;
4959d5ac70f0Sopenharmony_ci		}
4960d5ac70f0Sopenharmony_ci		case SND_CONFIG_TYPE_INTEGER64:
4961d5ac70f0Sopenharmony_ci		{
4962d5ac70f0Sopenharmony_ci			long long v;
4963d5ac70f0Sopenharmony_ci			err = snd_config_get_integer64(src, &v);
4964d5ac70f0Sopenharmony_ci			assert(err >= 0);
4965d5ac70f0Sopenharmony_ci			snd_config_set_integer64(*dst, v);
4966d5ac70f0Sopenharmony_ci			break;
4967d5ac70f0Sopenharmony_ci		}
4968d5ac70f0Sopenharmony_ci		case SND_CONFIG_TYPE_REAL:
4969d5ac70f0Sopenharmony_ci		{
4970d5ac70f0Sopenharmony_ci			double v;
4971d5ac70f0Sopenharmony_ci			err = snd_config_get_real(src, &v);
4972d5ac70f0Sopenharmony_ci			assert(err >= 0);
4973d5ac70f0Sopenharmony_ci			snd_config_set_real(*dst, v);
4974d5ac70f0Sopenharmony_ci			break;
4975d5ac70f0Sopenharmony_ci		}
4976d5ac70f0Sopenharmony_ci		case SND_CONFIG_TYPE_STRING:
4977d5ac70f0Sopenharmony_ci		{
4978d5ac70f0Sopenharmony_ci			const char *s;
4979d5ac70f0Sopenharmony_ci			err = snd_config_get_string(src, &s);
4980d5ac70f0Sopenharmony_ci			assert(err >= 0);
4981d5ac70f0Sopenharmony_ci			err = snd_config_set_string(*dst, s);
4982d5ac70f0Sopenharmony_ci			if (err < 0)
4983d5ac70f0Sopenharmony_ci				return err;
4984d5ac70f0Sopenharmony_ci			break;
4985d5ac70f0Sopenharmony_ci		}
4986d5ac70f0Sopenharmony_ci		default:
4987d5ac70f0Sopenharmony_ci			assert(0);
4988d5ac70f0Sopenharmony_ci		}
4989d5ac70f0Sopenharmony_ci		break;
4990d5ac70f0Sopenharmony_ci	default:
4991d5ac70f0Sopenharmony_ci		break;
4992d5ac70f0Sopenharmony_ci	}
4993d5ac70f0Sopenharmony_ci	return 1;
4994d5ac70f0Sopenharmony_ci}
4995d5ac70f0Sopenharmony_ci
4996d5ac70f0Sopenharmony_ci/**
4997d5ac70f0Sopenharmony_ci * \brief Creates a copy of a configuration node.
4998d5ac70f0Sopenharmony_ci * \param[out] dst The function puts the handle to the new configuration
4999d5ac70f0Sopenharmony_ci *                 node at the address specified by \a dst.
5000d5ac70f0Sopenharmony_ci * \param[in] src Handle to the source configuration node.
5001d5ac70f0Sopenharmony_ci * \return A non-negative value if successful, otherwise a negative error code.
5002d5ac70f0Sopenharmony_ci *
5003d5ac70f0Sopenharmony_ci * This function creates a deep copy, i.e., if \a src is a compound
5004d5ac70f0Sopenharmony_ci * node, all children are copied recursively.
5005d5ac70f0Sopenharmony_ci *
5006d5ac70f0Sopenharmony_ci * \par Errors:
5007d5ac70f0Sopenharmony_ci * <dl>
5008d5ac70f0Sopenharmony_ci * <dt>-ENOMEM<dd>Out of memory.
5009d5ac70f0Sopenharmony_ci * </dl>
5010d5ac70f0Sopenharmony_ci *
5011d5ac70f0Sopenharmony_ci * \par Conforming to:
5012d5ac70f0Sopenharmony_ci * LSB 3.2
5013d5ac70f0Sopenharmony_ci */
5014d5ac70f0Sopenharmony_ciint snd_config_copy(snd_config_t **dst,
5015d5ac70f0Sopenharmony_ci		    snd_config_t *src)
5016d5ac70f0Sopenharmony_ci{
5017d5ac70f0Sopenharmony_ci	return snd_config_walk(src, NULL, dst, _snd_config_copy, NULL, NULL);
5018d5ac70f0Sopenharmony_ci}
5019d5ac70f0Sopenharmony_ci
5020d5ac70f0Sopenharmony_cistatic int _snd_config_expand_vars(snd_config_t **dst, const char *s, void *private_data)
5021d5ac70f0Sopenharmony_ci{
5022d5ac70f0Sopenharmony_ci	snd_config_t *val, *vars = private_data;
5023d5ac70f0Sopenharmony_ci	if (snd_config_search(vars, s, &val) < 0) {
5024d5ac70f0Sopenharmony_ci		*dst = NULL;
5025d5ac70f0Sopenharmony_ci		return 0;
5026d5ac70f0Sopenharmony_ci	}
5027d5ac70f0Sopenharmony_ci	return snd_config_copy(dst, val);
5028d5ac70f0Sopenharmony_ci}
5029d5ac70f0Sopenharmony_ci
5030d5ac70f0Sopenharmony_cistatic int _snd_config_expand(snd_config_t *src,
5031d5ac70f0Sopenharmony_ci			      snd_config_t *root ATTRIBUTE_UNUSED,
5032d5ac70f0Sopenharmony_ci			      snd_config_t **dst,
5033d5ac70f0Sopenharmony_ci			      snd_config_walk_pass_t pass,
5034d5ac70f0Sopenharmony_ci			      snd_config_expand_fcn_t fcn,
5035d5ac70f0Sopenharmony_ci			      void *private_data)
5036d5ac70f0Sopenharmony_ci{
5037d5ac70f0Sopenharmony_ci	int err;
5038d5ac70f0Sopenharmony_ci	const char *id = src->id;
5039d5ac70f0Sopenharmony_ci	snd_config_type_t type = snd_config_get_type(src);
5040d5ac70f0Sopenharmony_ci	switch (pass) {
5041d5ac70f0Sopenharmony_ci	case SND_CONFIG_WALK_PASS_PRE:
5042d5ac70f0Sopenharmony_ci	{
5043d5ac70f0Sopenharmony_ci		if (id && strcmp(id, "@args") == 0)
5044d5ac70f0Sopenharmony_ci			return 0;
5045d5ac70f0Sopenharmony_ci		err = snd_config_make_compound(dst, id, src->u.compound.join);
5046d5ac70f0Sopenharmony_ci		if (err < 0)
5047d5ac70f0Sopenharmony_ci			return err;
5048d5ac70f0Sopenharmony_ci		break;
5049d5ac70f0Sopenharmony_ci	}
5050d5ac70f0Sopenharmony_ci	case SND_CONFIG_WALK_PASS_LEAF:
5051d5ac70f0Sopenharmony_ci		switch (type) {
5052d5ac70f0Sopenharmony_ci		case SND_CONFIG_TYPE_INTEGER:
5053d5ac70f0Sopenharmony_ci		{
5054d5ac70f0Sopenharmony_ci			long v;
5055d5ac70f0Sopenharmony_ci			err = snd_config_get_integer(src, &v);
5056d5ac70f0Sopenharmony_ci			assert(err >= 0);
5057d5ac70f0Sopenharmony_ci			err = snd_config_imake_integer(dst, id, v);
5058d5ac70f0Sopenharmony_ci			if (err < 0)
5059d5ac70f0Sopenharmony_ci				return err;
5060d5ac70f0Sopenharmony_ci			break;
5061d5ac70f0Sopenharmony_ci		}
5062d5ac70f0Sopenharmony_ci		case SND_CONFIG_TYPE_INTEGER64:
5063d5ac70f0Sopenharmony_ci		{
5064d5ac70f0Sopenharmony_ci			long long v;
5065d5ac70f0Sopenharmony_ci			err = snd_config_get_integer64(src, &v);
5066d5ac70f0Sopenharmony_ci			assert(err >= 0);
5067d5ac70f0Sopenharmony_ci			err = snd_config_imake_integer64(dst, id, v);
5068d5ac70f0Sopenharmony_ci			if (err < 0)
5069d5ac70f0Sopenharmony_ci				return err;
5070d5ac70f0Sopenharmony_ci			break;
5071d5ac70f0Sopenharmony_ci		}
5072d5ac70f0Sopenharmony_ci		case SND_CONFIG_TYPE_REAL:
5073d5ac70f0Sopenharmony_ci		{
5074d5ac70f0Sopenharmony_ci			double v;
5075d5ac70f0Sopenharmony_ci			err = snd_config_get_real(src, &v);
5076d5ac70f0Sopenharmony_ci			assert(err >= 0);
5077d5ac70f0Sopenharmony_ci			err = snd_config_imake_real(dst, id, v);
5078d5ac70f0Sopenharmony_ci			if (err < 0)
5079d5ac70f0Sopenharmony_ci				return err;
5080d5ac70f0Sopenharmony_ci			break;
5081d5ac70f0Sopenharmony_ci		}
5082d5ac70f0Sopenharmony_ci		case SND_CONFIG_TYPE_STRING:
5083d5ac70f0Sopenharmony_ci		{
5084d5ac70f0Sopenharmony_ci			const char *s;
5085d5ac70f0Sopenharmony_ci			snd_config_t *vars = private_data;
5086d5ac70f0Sopenharmony_ci			snd_config_get_string(src, &s);
5087d5ac70f0Sopenharmony_ci			if (s && *s == '$') {
5088d5ac70f0Sopenharmony_ci				err = snd_config_evaluate_string(dst, s, fcn, vars);
5089d5ac70f0Sopenharmony_ci				if (err < 0)
5090d5ac70f0Sopenharmony_ci					return err;
5091d5ac70f0Sopenharmony_ci				if (*dst == NULL)
5092d5ac70f0Sopenharmony_ci					return 0;
5093d5ac70f0Sopenharmony_ci				err = snd_config_set_id(*dst, id);
5094d5ac70f0Sopenharmony_ci				if (err < 0) {
5095d5ac70f0Sopenharmony_ci					snd_config_delete(*dst);
5096d5ac70f0Sopenharmony_ci					return err;
5097d5ac70f0Sopenharmony_ci				}
5098d5ac70f0Sopenharmony_ci			} else {
5099d5ac70f0Sopenharmony_ci				err = snd_config_imake_string(dst, id, s);
5100d5ac70f0Sopenharmony_ci				if (err < 0)
5101d5ac70f0Sopenharmony_ci					return err;
5102d5ac70f0Sopenharmony_ci			}
5103d5ac70f0Sopenharmony_ci			break;
5104d5ac70f0Sopenharmony_ci		}
5105d5ac70f0Sopenharmony_ci		default:
5106d5ac70f0Sopenharmony_ci			assert(0);
5107d5ac70f0Sopenharmony_ci		}
5108d5ac70f0Sopenharmony_ci		break;
5109d5ac70f0Sopenharmony_ci	default:
5110d5ac70f0Sopenharmony_ci		break;
5111d5ac70f0Sopenharmony_ci	}
5112d5ac70f0Sopenharmony_ci	return 1;
5113d5ac70f0Sopenharmony_ci}
5114d5ac70f0Sopenharmony_ci
5115d5ac70f0Sopenharmony_cistatic int _snd_config_evaluate(snd_config_t *src,
5116d5ac70f0Sopenharmony_ci				snd_config_t *root,
5117d5ac70f0Sopenharmony_ci				snd_config_t **dst ATTRIBUTE_UNUSED,
5118d5ac70f0Sopenharmony_ci				snd_config_walk_pass_t pass,
5119d5ac70f0Sopenharmony_ci				snd_config_expand_fcn_t fcn ATTRIBUTE_UNUSED,
5120d5ac70f0Sopenharmony_ci				void *private_data)
5121d5ac70f0Sopenharmony_ci{
5122d5ac70f0Sopenharmony_ci	int err;
5123d5ac70f0Sopenharmony_ci	if (pass == SND_CONFIG_WALK_PASS_PRE) {
5124d5ac70f0Sopenharmony_ci		char *buf = NULL, errbuf[256];
5125d5ac70f0Sopenharmony_ci		const char *lib = NULL, *func_name = NULL;
5126d5ac70f0Sopenharmony_ci		const char *str;
5127d5ac70f0Sopenharmony_ci		int (*func)(snd_config_t **dst, snd_config_t *root,
5128d5ac70f0Sopenharmony_ci			    snd_config_t *src, snd_config_t *private_data) = NULL;
5129d5ac70f0Sopenharmony_ci		void *h = NULL;
5130d5ac70f0Sopenharmony_ci		snd_config_t *c, *func_conf = NULL;
5131d5ac70f0Sopenharmony_ci		err = snd_config_search(src, "@func", &c);
5132d5ac70f0Sopenharmony_ci		if (err < 0)
5133d5ac70f0Sopenharmony_ci			return 1;
5134d5ac70f0Sopenharmony_ci		err = snd_config_get_string(c, &str);
5135d5ac70f0Sopenharmony_ci		if (err < 0) {
5136d5ac70f0Sopenharmony_ci			SNDERR("Invalid type for @func");
5137d5ac70f0Sopenharmony_ci			return err;
5138d5ac70f0Sopenharmony_ci		}
5139d5ac70f0Sopenharmony_ci		assert(str);
5140d5ac70f0Sopenharmony_ci		err = snd_config_search_definition(root, "func", str, &func_conf);
5141d5ac70f0Sopenharmony_ci		if (err >= 0) {
5142d5ac70f0Sopenharmony_ci			snd_config_iterator_t i, next;
5143d5ac70f0Sopenharmony_ci			if (snd_config_get_type(func_conf) != SND_CONFIG_TYPE_COMPOUND) {
5144d5ac70f0Sopenharmony_ci				SNDERR("Invalid type for func %s definition", str);
5145d5ac70f0Sopenharmony_ci				err = -EINVAL;
5146d5ac70f0Sopenharmony_ci				goto _err;
5147d5ac70f0Sopenharmony_ci			}
5148d5ac70f0Sopenharmony_ci			snd_config_for_each(i, next, func_conf) {
5149d5ac70f0Sopenharmony_ci				snd_config_t *n = snd_config_iterator_entry(i);
5150d5ac70f0Sopenharmony_ci				const char *id = n->id;
5151d5ac70f0Sopenharmony_ci				if (strcmp(id, "comment") == 0)
5152d5ac70f0Sopenharmony_ci					continue;
5153d5ac70f0Sopenharmony_ci				if (strcmp(id, "lib") == 0) {
5154d5ac70f0Sopenharmony_ci					err = snd_config_get_string(n, &lib);
5155d5ac70f0Sopenharmony_ci					if (err < 0) {
5156d5ac70f0Sopenharmony_ci						SNDERR("Invalid type for %s", id);
5157d5ac70f0Sopenharmony_ci						goto _err;
5158d5ac70f0Sopenharmony_ci					}
5159d5ac70f0Sopenharmony_ci					continue;
5160d5ac70f0Sopenharmony_ci				}
5161d5ac70f0Sopenharmony_ci				if (strcmp(id, "func") == 0) {
5162d5ac70f0Sopenharmony_ci					err = snd_config_get_string(n, &func_name);
5163d5ac70f0Sopenharmony_ci					if (err < 0) {
5164d5ac70f0Sopenharmony_ci						SNDERR("Invalid type for %s", id);
5165d5ac70f0Sopenharmony_ci						goto _err;
5166d5ac70f0Sopenharmony_ci					}
5167d5ac70f0Sopenharmony_ci					continue;
5168d5ac70f0Sopenharmony_ci				}
5169d5ac70f0Sopenharmony_ci				SNDERR("Unknown field %s", id);
5170d5ac70f0Sopenharmony_ci			}
5171d5ac70f0Sopenharmony_ci		}
5172d5ac70f0Sopenharmony_ci		if (!func_name) {
5173d5ac70f0Sopenharmony_ci			int len = 9 + strlen(str) + 1;
5174d5ac70f0Sopenharmony_ci			buf = malloc(len);
5175d5ac70f0Sopenharmony_ci			if (! buf) {
5176d5ac70f0Sopenharmony_ci				err = -ENOMEM;
5177d5ac70f0Sopenharmony_ci				goto _err;
5178d5ac70f0Sopenharmony_ci			}
5179d5ac70f0Sopenharmony_ci			snprintf(buf, len, "snd_func_%s", str);
5180d5ac70f0Sopenharmony_ci			buf[len-1] = '\0';
5181d5ac70f0Sopenharmony_ci			func_name = buf;
5182d5ac70f0Sopenharmony_ci		}
5183d5ac70f0Sopenharmony_ci		h = INTERNAL(snd_dlopen)(lib, RTLD_NOW, errbuf, sizeof(errbuf));
5184d5ac70f0Sopenharmony_ci		if (h)
5185d5ac70f0Sopenharmony_ci			func = snd_dlsym(h, func_name, SND_DLSYM_VERSION(SND_CONFIG_DLSYM_VERSION_EVALUATE));
5186d5ac70f0Sopenharmony_ci		err = 0;
5187d5ac70f0Sopenharmony_ci		if (!h) {
5188d5ac70f0Sopenharmony_ci			SNDERR("Cannot open shared library %s (%s)", lib, errbuf);
5189d5ac70f0Sopenharmony_ci			err = -ENOENT;
5190d5ac70f0Sopenharmony_ci			goto _errbuf;
5191d5ac70f0Sopenharmony_ci		} else if (!func) {
5192d5ac70f0Sopenharmony_ci			SNDERR("symbol %s is not defined inside %s", func_name, lib);
5193d5ac70f0Sopenharmony_ci			snd_dlclose(h);
5194d5ac70f0Sopenharmony_ci			err = -ENXIO;
5195d5ac70f0Sopenharmony_ci			goto _errbuf;
5196d5ac70f0Sopenharmony_ci		}
5197d5ac70f0Sopenharmony_ci	       _err:
5198d5ac70f0Sopenharmony_ci		if (func_conf)
5199d5ac70f0Sopenharmony_ci			snd_config_delete(func_conf);
5200d5ac70f0Sopenharmony_ci		if (err >= 0) {
5201d5ac70f0Sopenharmony_ci			snd_config_t *eval;
5202d5ac70f0Sopenharmony_ci			err = func(&eval, root, src, private_data);
5203d5ac70f0Sopenharmony_ci			if (err < 0)
5204d5ac70f0Sopenharmony_ci				SNDERR("function %s returned error: %s", func_name, snd_strerror(err));
5205d5ac70f0Sopenharmony_ci			snd_dlclose(h);
5206d5ac70f0Sopenharmony_ci			if (err >= 0 && eval)
5207d5ac70f0Sopenharmony_ci				err = snd_config_substitute(src, eval);
5208d5ac70f0Sopenharmony_ci		}
5209d5ac70f0Sopenharmony_ci	       _errbuf:
5210d5ac70f0Sopenharmony_ci		free(buf);
5211d5ac70f0Sopenharmony_ci		if (err < 0)
5212d5ac70f0Sopenharmony_ci			return err;
5213d5ac70f0Sopenharmony_ci		return 0;
5214d5ac70f0Sopenharmony_ci	}
5215d5ac70f0Sopenharmony_ci	return 1;
5216d5ac70f0Sopenharmony_ci}
5217d5ac70f0Sopenharmony_ci
5218d5ac70f0Sopenharmony_ci/**
5219d5ac70f0Sopenharmony_ci * \brief Evaluates a configuration node at runtime.
5220d5ac70f0Sopenharmony_ci * \param[in,out] config Handle to the source configuration node.
5221d5ac70f0Sopenharmony_ci * \param[in] root Handle to the root of the source configuration.
5222d5ac70f0Sopenharmony_ci * \param[in] private_data Handle to the private data node for runtime evaluation.
5223d5ac70f0Sopenharmony_ci * \param result Must be \c NULL.
5224d5ac70f0Sopenharmony_ci * \return A non-negative value if successful, otherwise a negative error code.
5225d5ac70f0Sopenharmony_ci *
5226d5ac70f0Sopenharmony_ci * This function evaluates any functions (\c \@func) in \a config and
5227d5ac70f0Sopenharmony_ci * replaces those nodes with the respective function results.
5228d5ac70f0Sopenharmony_ci */
5229d5ac70f0Sopenharmony_ciint snd_config_evaluate(snd_config_t *config, snd_config_t *root,
5230d5ac70f0Sopenharmony_ci		        snd_config_t *private_data, snd_config_t **result)
5231d5ac70f0Sopenharmony_ci{
5232d5ac70f0Sopenharmony_ci	/* FIXME: Only in place evaluation is currently implemented */
5233d5ac70f0Sopenharmony_ci	assert(result == NULL);
5234d5ac70f0Sopenharmony_ci	return snd_config_walk(config, root, result, _snd_config_evaluate, NULL, private_data);
5235d5ac70f0Sopenharmony_ci}
5236d5ac70f0Sopenharmony_ci
5237d5ac70f0Sopenharmony_cistatic int load_defaults(snd_config_t *subs, snd_config_t *defs)
5238d5ac70f0Sopenharmony_ci{
5239d5ac70f0Sopenharmony_ci	snd_config_iterator_t d, dnext;
5240d5ac70f0Sopenharmony_ci	snd_config_for_each(d, dnext, defs) {
5241d5ac70f0Sopenharmony_ci		snd_config_t *def = snd_config_iterator_entry(d);
5242d5ac70f0Sopenharmony_ci		snd_config_iterator_t f, fnext;
5243d5ac70f0Sopenharmony_ci		if (snd_config_get_type(def) != SND_CONFIG_TYPE_COMPOUND)
5244d5ac70f0Sopenharmony_ci			continue;
5245d5ac70f0Sopenharmony_ci		snd_config_for_each(f, fnext, def) {
5246d5ac70f0Sopenharmony_ci			snd_config_t *fld = snd_config_iterator_entry(f);
5247d5ac70f0Sopenharmony_ci			const char *id = fld->id;
5248d5ac70f0Sopenharmony_ci			if (strcmp(id, "type") == 0)
5249d5ac70f0Sopenharmony_ci				continue;
5250d5ac70f0Sopenharmony_ci			if (strcmp(id, "default") == 0) {
5251d5ac70f0Sopenharmony_ci				snd_config_t *deflt;
5252d5ac70f0Sopenharmony_ci				int err;
5253d5ac70f0Sopenharmony_ci				err = snd_config_copy(&deflt, fld);
5254d5ac70f0Sopenharmony_ci				if (err < 0)
5255d5ac70f0Sopenharmony_ci					return err;
5256d5ac70f0Sopenharmony_ci				err = snd_config_set_id(deflt, def->id);
5257d5ac70f0Sopenharmony_ci				if (err < 0) {
5258d5ac70f0Sopenharmony_ci					snd_config_delete(deflt);
5259d5ac70f0Sopenharmony_ci					return err;
5260d5ac70f0Sopenharmony_ci				}
5261d5ac70f0Sopenharmony_ci				err = snd_config_add(subs, deflt);
5262d5ac70f0Sopenharmony_ci				if (err < 0) {
5263d5ac70f0Sopenharmony_ci					snd_config_delete(deflt);
5264d5ac70f0Sopenharmony_ci					return err;
5265d5ac70f0Sopenharmony_ci				}
5266d5ac70f0Sopenharmony_ci				continue;
5267d5ac70f0Sopenharmony_ci			}
5268d5ac70f0Sopenharmony_ci			SNDERR("Unknown field %s", id);
5269d5ac70f0Sopenharmony_ci			return -EINVAL;
5270d5ac70f0Sopenharmony_ci		}
5271d5ac70f0Sopenharmony_ci	}
5272d5ac70f0Sopenharmony_ci	return 0;
5273d5ac70f0Sopenharmony_ci}
5274d5ac70f0Sopenharmony_ci
5275d5ac70f0Sopenharmony_cistatic void skip_blank(const char **ptr)
5276d5ac70f0Sopenharmony_ci{
5277d5ac70f0Sopenharmony_ci	while (1) {
5278d5ac70f0Sopenharmony_ci		switch (**ptr) {
5279d5ac70f0Sopenharmony_ci		case ' ':
5280d5ac70f0Sopenharmony_ci		case '\f':
5281d5ac70f0Sopenharmony_ci		case '\t':
5282d5ac70f0Sopenharmony_ci		case '\n':
5283d5ac70f0Sopenharmony_ci		case '\r':
5284d5ac70f0Sopenharmony_ci			break;
5285d5ac70f0Sopenharmony_ci		default:
5286d5ac70f0Sopenharmony_ci			return;
5287d5ac70f0Sopenharmony_ci		}
5288d5ac70f0Sopenharmony_ci		(*ptr)++;
5289d5ac70f0Sopenharmony_ci	}
5290d5ac70f0Sopenharmony_ci}
5291d5ac70f0Sopenharmony_ci
5292d5ac70f0Sopenharmony_cistatic int parse_char(const char **ptr)
5293d5ac70f0Sopenharmony_ci{
5294d5ac70f0Sopenharmony_ci	int c;
5295d5ac70f0Sopenharmony_ci	assert(**ptr == '\\');
5296d5ac70f0Sopenharmony_ci	(*ptr)++;
5297d5ac70f0Sopenharmony_ci	c = **ptr;
5298d5ac70f0Sopenharmony_ci	switch (c) {
5299d5ac70f0Sopenharmony_ci	case 'n':
5300d5ac70f0Sopenharmony_ci		c = '\n';
5301d5ac70f0Sopenharmony_ci		break;
5302d5ac70f0Sopenharmony_ci	case 't':
5303d5ac70f0Sopenharmony_ci		c = '\t';
5304d5ac70f0Sopenharmony_ci		break;
5305d5ac70f0Sopenharmony_ci	case 'v':
5306d5ac70f0Sopenharmony_ci		c = '\v';
5307d5ac70f0Sopenharmony_ci		break;
5308d5ac70f0Sopenharmony_ci	case 'b':
5309d5ac70f0Sopenharmony_ci		c = '\b';
5310d5ac70f0Sopenharmony_ci		break;
5311d5ac70f0Sopenharmony_ci	case 'r':
5312d5ac70f0Sopenharmony_ci		c = '\r';
5313d5ac70f0Sopenharmony_ci		break;
5314d5ac70f0Sopenharmony_ci	case 'f':
5315d5ac70f0Sopenharmony_ci		c = '\f';
5316d5ac70f0Sopenharmony_ci		break;
5317d5ac70f0Sopenharmony_ci	case '0': case '1': case '2': case '3':
5318d5ac70f0Sopenharmony_ci	case '4': case '5': case '6': case '7':
5319d5ac70f0Sopenharmony_ci	{
5320d5ac70f0Sopenharmony_ci		int num = c - '0';
5321d5ac70f0Sopenharmony_ci		int i = 1;
5322d5ac70f0Sopenharmony_ci		(*ptr)++;
5323d5ac70f0Sopenharmony_ci		do {
5324d5ac70f0Sopenharmony_ci			c = **ptr;
5325d5ac70f0Sopenharmony_ci			if (c < '0' || c > '7')
5326d5ac70f0Sopenharmony_ci				break;
5327d5ac70f0Sopenharmony_ci			num = num * 8 + c - '0';
5328d5ac70f0Sopenharmony_ci			i++;
5329d5ac70f0Sopenharmony_ci			(*ptr)++;
5330d5ac70f0Sopenharmony_ci		} while (i < 3);
5331d5ac70f0Sopenharmony_ci		return num;
5332d5ac70f0Sopenharmony_ci	}
5333d5ac70f0Sopenharmony_ci	default:
5334d5ac70f0Sopenharmony_ci		break;
5335d5ac70f0Sopenharmony_ci	}
5336d5ac70f0Sopenharmony_ci	(*ptr)++;
5337d5ac70f0Sopenharmony_ci	return c;
5338d5ac70f0Sopenharmony_ci}
5339d5ac70f0Sopenharmony_ci
5340d5ac70f0Sopenharmony_cistatic int parse_id(const char **ptr)
5341d5ac70f0Sopenharmony_ci{
5342d5ac70f0Sopenharmony_ci	if (!**ptr)
5343d5ac70f0Sopenharmony_ci		return -EINVAL;
5344d5ac70f0Sopenharmony_ci	while (1) {
5345d5ac70f0Sopenharmony_ci		switch (**ptr) {
5346d5ac70f0Sopenharmony_ci		case '\f':
5347d5ac70f0Sopenharmony_ci		case '\t':
5348d5ac70f0Sopenharmony_ci		case '\n':
5349d5ac70f0Sopenharmony_ci		case '\r':
5350d5ac70f0Sopenharmony_ci		case ',':
5351d5ac70f0Sopenharmony_ci		case '=':
5352d5ac70f0Sopenharmony_ci		case '\0':
5353d5ac70f0Sopenharmony_ci			return 0;
5354d5ac70f0Sopenharmony_ci		default:
5355d5ac70f0Sopenharmony_ci			break;
5356d5ac70f0Sopenharmony_ci		}
5357d5ac70f0Sopenharmony_ci		(*ptr)++;
5358d5ac70f0Sopenharmony_ci	}
5359d5ac70f0Sopenharmony_ci}
5360d5ac70f0Sopenharmony_ci
5361d5ac70f0Sopenharmony_cistatic int parse_string(const char **ptr, char **val)
5362d5ac70f0Sopenharmony_ci{
5363d5ac70f0Sopenharmony_ci	const size_t bufsize = 256;
5364d5ac70f0Sopenharmony_ci	char _buf[bufsize];
5365d5ac70f0Sopenharmony_ci	char *buf = _buf;
5366d5ac70f0Sopenharmony_ci	size_t alloc = bufsize;
5367d5ac70f0Sopenharmony_ci	char delim = **ptr;
5368d5ac70f0Sopenharmony_ci	size_t idx = 0;
5369d5ac70f0Sopenharmony_ci	(*ptr)++;
5370d5ac70f0Sopenharmony_ci	while (1) {
5371d5ac70f0Sopenharmony_ci		int c = **ptr;
5372d5ac70f0Sopenharmony_ci		switch (c) {
5373d5ac70f0Sopenharmony_ci		case '\0':
5374d5ac70f0Sopenharmony_ci			SNDERR("Unterminated string");
5375d5ac70f0Sopenharmony_ci			return -EINVAL;
5376d5ac70f0Sopenharmony_ci		case '\\':
5377d5ac70f0Sopenharmony_ci			c = parse_char(ptr);
5378d5ac70f0Sopenharmony_ci			if (c < 0) {
5379d5ac70f0Sopenharmony_ci				if (alloc > bufsize)
5380d5ac70f0Sopenharmony_ci					free(buf);
5381d5ac70f0Sopenharmony_ci				return c;
5382d5ac70f0Sopenharmony_ci			}
5383d5ac70f0Sopenharmony_ci			break;
5384d5ac70f0Sopenharmony_ci		default:
5385d5ac70f0Sopenharmony_ci			(*ptr)++;
5386d5ac70f0Sopenharmony_ci			if (c == delim) {
5387d5ac70f0Sopenharmony_ci				*val = malloc(idx + 1);
5388d5ac70f0Sopenharmony_ci				if (!*val)
5389d5ac70f0Sopenharmony_ci					return -ENOMEM;
5390d5ac70f0Sopenharmony_ci				memcpy(*val, buf, idx);
5391d5ac70f0Sopenharmony_ci				(*val)[idx] = 0;
5392d5ac70f0Sopenharmony_ci				if (alloc > bufsize)
5393d5ac70f0Sopenharmony_ci					free(buf);
5394d5ac70f0Sopenharmony_ci				return 0;
5395d5ac70f0Sopenharmony_ci			}
5396d5ac70f0Sopenharmony_ci		}
5397d5ac70f0Sopenharmony_ci		if (idx >= alloc) {
5398d5ac70f0Sopenharmony_ci			size_t old_alloc = alloc;
5399d5ac70f0Sopenharmony_ci			alloc *= 2;
5400d5ac70f0Sopenharmony_ci			if (old_alloc == bufsize) {
5401d5ac70f0Sopenharmony_ci				buf = malloc(alloc);
5402d5ac70f0Sopenharmony_ci				if (!buf)
5403d5ac70f0Sopenharmony_ci					return -ENOMEM;
5404d5ac70f0Sopenharmony_ci				memcpy(buf, _buf, old_alloc);
5405d5ac70f0Sopenharmony_ci			} else {
5406d5ac70f0Sopenharmony_ci				char *buf2 = realloc(buf, alloc);
5407d5ac70f0Sopenharmony_ci				if (!buf2) {
5408d5ac70f0Sopenharmony_ci					free(buf);
5409d5ac70f0Sopenharmony_ci					return -ENOMEM;
5410d5ac70f0Sopenharmony_ci				}
5411d5ac70f0Sopenharmony_ci				buf = buf2;
5412d5ac70f0Sopenharmony_ci			}
5413d5ac70f0Sopenharmony_ci		}
5414d5ac70f0Sopenharmony_ci		buf[idx++] = c;
5415d5ac70f0Sopenharmony_ci	}
5416d5ac70f0Sopenharmony_ci}
5417d5ac70f0Sopenharmony_ci
5418d5ac70f0Sopenharmony_ci
5419d5ac70f0Sopenharmony_ci/* Parse var=val or val */
5420d5ac70f0Sopenharmony_cistatic int parse_arg(const char **ptr, unsigned int *varlen, char **val)
5421d5ac70f0Sopenharmony_ci{
5422d5ac70f0Sopenharmony_ci	const char *str;
5423d5ac70f0Sopenharmony_ci	int err, vallen;
5424d5ac70f0Sopenharmony_ci	skip_blank(ptr);
5425d5ac70f0Sopenharmony_ci	str = *ptr;
5426d5ac70f0Sopenharmony_ci	if (*str == '"' || *str == '\'') {
5427d5ac70f0Sopenharmony_ci		err = parse_string(ptr, val);
5428d5ac70f0Sopenharmony_ci		if (err < 0)
5429d5ac70f0Sopenharmony_ci			return err;
5430d5ac70f0Sopenharmony_ci		*varlen = 0;
5431d5ac70f0Sopenharmony_ci		return 0;
5432d5ac70f0Sopenharmony_ci	}
5433d5ac70f0Sopenharmony_ci	err = parse_id(ptr);
5434d5ac70f0Sopenharmony_ci	if (err < 0)
5435d5ac70f0Sopenharmony_ci		return err;
5436d5ac70f0Sopenharmony_ci	vallen = *ptr - str;
5437d5ac70f0Sopenharmony_ci	skip_blank(ptr);
5438d5ac70f0Sopenharmony_ci	if (**ptr != '=') {
5439d5ac70f0Sopenharmony_ci		*varlen = 0;
5440d5ac70f0Sopenharmony_ci		goto _value;
5441d5ac70f0Sopenharmony_ci	}
5442d5ac70f0Sopenharmony_ci	*varlen = vallen;
5443d5ac70f0Sopenharmony_ci	(*ptr)++;
5444d5ac70f0Sopenharmony_ci	skip_blank(ptr);
5445d5ac70f0Sopenharmony_ci	str = *ptr;
5446d5ac70f0Sopenharmony_ci	if (*str == '"' || *str == '\'') {
5447d5ac70f0Sopenharmony_ci		err = parse_string(ptr, val);
5448d5ac70f0Sopenharmony_ci		if (err < 0)
5449d5ac70f0Sopenharmony_ci			return err;
5450d5ac70f0Sopenharmony_ci		return 0;
5451d5ac70f0Sopenharmony_ci	}
5452d5ac70f0Sopenharmony_ci	err = parse_id(ptr);
5453d5ac70f0Sopenharmony_ci	if (err < 0)
5454d5ac70f0Sopenharmony_ci		return err;
5455d5ac70f0Sopenharmony_ci	vallen = *ptr - str;
5456d5ac70f0Sopenharmony_ci _value:
5457d5ac70f0Sopenharmony_ci	*val = malloc(vallen + 1);
5458d5ac70f0Sopenharmony_ci	if (!*val)
5459d5ac70f0Sopenharmony_ci		return -ENOMEM;
5460d5ac70f0Sopenharmony_ci	memcpy(*val, str, vallen);
5461d5ac70f0Sopenharmony_ci	(*val)[vallen] = 0;
5462d5ac70f0Sopenharmony_ci	return 0;
5463d5ac70f0Sopenharmony_ci}
5464d5ac70f0Sopenharmony_ci
5465d5ac70f0Sopenharmony_ci
5466d5ac70f0Sopenharmony_ci/* val1, val2, ...
5467d5ac70f0Sopenharmony_ci * var1=val1,var2=val2,...
5468d5ac70f0Sopenharmony_ci * { conf syntax }
5469d5ac70f0Sopenharmony_ci */
5470d5ac70f0Sopenharmony_cistatic int parse_args(snd_config_t *subs, const char *str, snd_config_t *defs)
5471d5ac70f0Sopenharmony_ci{
5472d5ac70f0Sopenharmony_ci	int err;
5473d5ac70f0Sopenharmony_ci	int arg = 0;
5474d5ac70f0Sopenharmony_ci	if (str == NULL)
5475d5ac70f0Sopenharmony_ci		return 0;
5476d5ac70f0Sopenharmony_ci	skip_blank(&str);
5477d5ac70f0Sopenharmony_ci	if (!*str)
5478d5ac70f0Sopenharmony_ci		return 0;
5479d5ac70f0Sopenharmony_ci	if (*str == '{') {
5480d5ac70f0Sopenharmony_ci		int len = strlen(str);
5481d5ac70f0Sopenharmony_ci		snd_input_t *input;
5482d5ac70f0Sopenharmony_ci		snd_config_iterator_t i, next;
5483d5ac70f0Sopenharmony_ci		while (1) {
5484d5ac70f0Sopenharmony_ci			switch (str[--len]) {
5485d5ac70f0Sopenharmony_ci			case ' ':
5486d5ac70f0Sopenharmony_ci			case '\f':
5487d5ac70f0Sopenharmony_ci			case '\t':
5488d5ac70f0Sopenharmony_ci			case '\n':
5489d5ac70f0Sopenharmony_ci			case '\r':
5490d5ac70f0Sopenharmony_ci				continue;
5491d5ac70f0Sopenharmony_ci			default:
5492d5ac70f0Sopenharmony_ci				break;
5493d5ac70f0Sopenharmony_ci			}
5494d5ac70f0Sopenharmony_ci			break;
5495d5ac70f0Sopenharmony_ci		}
5496d5ac70f0Sopenharmony_ci		if (str[len] != '}')
5497d5ac70f0Sopenharmony_ci			return -EINVAL;
5498d5ac70f0Sopenharmony_ci		err = snd_input_buffer_open(&input, str + 1, len - 1);
5499d5ac70f0Sopenharmony_ci		if (err < 0)
5500d5ac70f0Sopenharmony_ci			return err;
5501d5ac70f0Sopenharmony_ci		err = snd_config_load_override(subs, input);
5502d5ac70f0Sopenharmony_ci		snd_input_close(input);
5503d5ac70f0Sopenharmony_ci		if (err < 0)
5504d5ac70f0Sopenharmony_ci			return err;
5505d5ac70f0Sopenharmony_ci		snd_config_for_each(i, next, subs) {
5506d5ac70f0Sopenharmony_ci			snd_config_t *n = snd_config_iterator_entry(i);
5507d5ac70f0Sopenharmony_ci			snd_config_t *d;
5508d5ac70f0Sopenharmony_ci			const char *id = n->id;
5509d5ac70f0Sopenharmony_ci			err = snd_config_search(defs, id, &d);
5510d5ac70f0Sopenharmony_ci			if (err < 0) {
5511d5ac70f0Sopenharmony_ci				SNDERR("Unknown parameter %s", id);
5512d5ac70f0Sopenharmony_ci				return err;
5513d5ac70f0Sopenharmony_ci			}
5514d5ac70f0Sopenharmony_ci		}
5515d5ac70f0Sopenharmony_ci		return 0;
5516d5ac70f0Sopenharmony_ci	}
5517d5ac70f0Sopenharmony_ci
5518d5ac70f0Sopenharmony_ci	while (1) {
5519d5ac70f0Sopenharmony_ci		char buf[256];
5520d5ac70f0Sopenharmony_ci		const char *var = buf;
5521d5ac70f0Sopenharmony_ci		unsigned int varlen;
5522d5ac70f0Sopenharmony_ci		snd_config_t *def, *sub, *typ;
5523d5ac70f0Sopenharmony_ci		const char *new = str;
5524d5ac70f0Sopenharmony_ci		const char *tmp;
5525d5ac70f0Sopenharmony_ci		char *val = NULL;
5526d5ac70f0Sopenharmony_ci
5527d5ac70f0Sopenharmony_ci		sub = NULL;
5528d5ac70f0Sopenharmony_ci		err = parse_arg(&new, &varlen, &val);
5529d5ac70f0Sopenharmony_ci		if (err < 0)
5530d5ac70f0Sopenharmony_ci			goto _err;
5531d5ac70f0Sopenharmony_ci		if (varlen > 0) {
5532d5ac70f0Sopenharmony_ci			assert(varlen < sizeof(buf));
5533d5ac70f0Sopenharmony_ci			memcpy(buf, str, varlen);
5534d5ac70f0Sopenharmony_ci			buf[varlen] = 0;
5535d5ac70f0Sopenharmony_ci		} else {
5536d5ac70f0Sopenharmony_ci			sprintf(buf, "%d", arg);
5537d5ac70f0Sopenharmony_ci		}
5538d5ac70f0Sopenharmony_ci		err = snd_config_search_alias(defs, NULL, var, &def);
5539d5ac70f0Sopenharmony_ci		if (err < 0) {
5540d5ac70f0Sopenharmony_ci			SNDERR("Unknown parameter %s", var);
5541d5ac70f0Sopenharmony_ci			goto _err;
5542d5ac70f0Sopenharmony_ci		}
5543d5ac70f0Sopenharmony_ci		if (snd_config_get_type(def) != SND_CONFIG_TYPE_COMPOUND) {
5544d5ac70f0Sopenharmony_ci			SNDERR("Parameter %s definition is not correct", var);
5545d5ac70f0Sopenharmony_ci			err = -EINVAL;
5546d5ac70f0Sopenharmony_ci			goto _err;
5547d5ac70f0Sopenharmony_ci		}
5548d5ac70f0Sopenharmony_ci		var = def->id;
5549d5ac70f0Sopenharmony_ci		err = snd_config_search(subs, var, &sub);
5550d5ac70f0Sopenharmony_ci		if (err >= 0)
5551d5ac70f0Sopenharmony_ci			snd_config_delete(sub);
5552d5ac70f0Sopenharmony_ci		sub = NULL;
5553d5ac70f0Sopenharmony_ci		err = snd_config_search(def, "type", &typ);
5554d5ac70f0Sopenharmony_ci		if (err < 0) {
5555d5ac70f0Sopenharmony_ci		_invalid_type:
5556d5ac70f0Sopenharmony_ci			SNDERR("Parameter %s definition is missing a valid type info", var);
5557d5ac70f0Sopenharmony_ci			goto _err;
5558d5ac70f0Sopenharmony_ci		}
5559d5ac70f0Sopenharmony_ci		err = snd_config_get_string(typ, &tmp);
5560d5ac70f0Sopenharmony_ci		if (err < 0 || !tmp)
5561d5ac70f0Sopenharmony_ci			goto _invalid_type;
5562d5ac70f0Sopenharmony_ci		if (strcmp(tmp, "integer") == 0) {
5563d5ac70f0Sopenharmony_ci			long v;
5564d5ac70f0Sopenharmony_ci			err = snd_config_make(&sub, var, SND_CONFIG_TYPE_INTEGER);
5565d5ac70f0Sopenharmony_ci			if (err < 0)
5566d5ac70f0Sopenharmony_ci				goto _err;
5567d5ac70f0Sopenharmony_ci			err = safe_strtol(val, &v);
5568d5ac70f0Sopenharmony_ci			if (err < 0) {
5569d5ac70f0Sopenharmony_ci				SNDERR("Parameter %s must be an integer", var);
5570d5ac70f0Sopenharmony_ci				goto _err;
5571d5ac70f0Sopenharmony_ci			}
5572d5ac70f0Sopenharmony_ci			err = snd_config_set_integer(sub, v);
5573d5ac70f0Sopenharmony_ci			if (err < 0)
5574d5ac70f0Sopenharmony_ci				goto _err;
5575d5ac70f0Sopenharmony_ci		} else if (strcmp(tmp, "integer64") == 0) {
5576d5ac70f0Sopenharmony_ci			long long v;
5577d5ac70f0Sopenharmony_ci			err = snd_config_make(&sub, var, SND_CONFIG_TYPE_INTEGER64);
5578d5ac70f0Sopenharmony_ci			if (err < 0)
5579d5ac70f0Sopenharmony_ci				goto _err;
5580d5ac70f0Sopenharmony_ci			err = safe_strtoll(val, &v);
5581d5ac70f0Sopenharmony_ci			if (err < 0) {
5582d5ac70f0Sopenharmony_ci				SNDERR("Parameter %s must be an integer", var);
5583d5ac70f0Sopenharmony_ci				goto _err;
5584d5ac70f0Sopenharmony_ci			}
5585d5ac70f0Sopenharmony_ci			err = snd_config_set_integer64(sub, v);
5586d5ac70f0Sopenharmony_ci			if (err < 0)
5587d5ac70f0Sopenharmony_ci				goto _err;
5588d5ac70f0Sopenharmony_ci		} else if (strcmp(tmp, "real") == 0) {
5589d5ac70f0Sopenharmony_ci			double v;
5590d5ac70f0Sopenharmony_ci			err = snd_config_make(&sub, var, SND_CONFIG_TYPE_REAL);
5591d5ac70f0Sopenharmony_ci			if (err < 0)
5592d5ac70f0Sopenharmony_ci				goto _err;
5593d5ac70f0Sopenharmony_ci			err = safe_strtod(val, &v);
5594d5ac70f0Sopenharmony_ci			if (err < 0) {
5595d5ac70f0Sopenharmony_ci				SNDERR("Parameter %s must be a real", var);
5596d5ac70f0Sopenharmony_ci				goto _err;
5597d5ac70f0Sopenharmony_ci			}
5598d5ac70f0Sopenharmony_ci			err = snd_config_set_real(sub, v);
5599d5ac70f0Sopenharmony_ci			if (err < 0)
5600d5ac70f0Sopenharmony_ci				goto _err;
5601d5ac70f0Sopenharmony_ci		} else if (strcmp(tmp, "string") == 0) {
5602d5ac70f0Sopenharmony_ci			err = snd_config_make(&sub, var, SND_CONFIG_TYPE_STRING);
5603d5ac70f0Sopenharmony_ci			if (err < 0)
5604d5ac70f0Sopenharmony_ci				goto _err;
5605d5ac70f0Sopenharmony_ci			err = snd_config_set_string(sub, val);
5606d5ac70f0Sopenharmony_ci			if (err < 0)
5607d5ac70f0Sopenharmony_ci				goto _err;
5608d5ac70f0Sopenharmony_ci		} else {
5609d5ac70f0Sopenharmony_ci			err = -EINVAL;
5610d5ac70f0Sopenharmony_ci			goto _invalid_type;
5611d5ac70f0Sopenharmony_ci		}
5612d5ac70f0Sopenharmony_ci		err = snd_config_set_id(sub, var);
5613d5ac70f0Sopenharmony_ci		if (err < 0)
5614d5ac70f0Sopenharmony_ci			goto _err;
5615d5ac70f0Sopenharmony_ci		err = snd_config_add(subs, sub);
5616d5ac70f0Sopenharmony_ci		if (err < 0) {
5617d5ac70f0Sopenharmony_ci		_err:
5618d5ac70f0Sopenharmony_ci			if (sub)
5619d5ac70f0Sopenharmony_ci				snd_config_delete(sub);
5620d5ac70f0Sopenharmony_ci			free(val);
5621d5ac70f0Sopenharmony_ci			return err;
5622d5ac70f0Sopenharmony_ci		}
5623d5ac70f0Sopenharmony_ci		free(val);
5624d5ac70f0Sopenharmony_ci		if (!*new)
5625d5ac70f0Sopenharmony_ci			break;
5626d5ac70f0Sopenharmony_ci		if (*new != ',')
5627d5ac70f0Sopenharmony_ci			return -EINVAL;
5628d5ac70f0Sopenharmony_ci		str = new + 1;
5629d5ac70f0Sopenharmony_ci		arg++;
5630d5ac70f0Sopenharmony_ci	}
5631d5ac70f0Sopenharmony_ci	return 0;
5632d5ac70f0Sopenharmony_ci}
5633d5ac70f0Sopenharmony_ci
5634d5ac70f0Sopenharmony_ci/**
5635d5ac70f0Sopenharmony_ci * \brief Expands a configuration node, applying arguments and functions.
5636d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration node.
5637d5ac70f0Sopenharmony_ci * \param[in] root Handle to the root configuration node.
5638d5ac70f0Sopenharmony_ci * \param[in] fcn Custom function to obtain the referred variable name
5639d5ac70f0Sopenharmony_ci * \param[in] private_data Private data node for the custom function
5640d5ac70f0Sopenharmony_ci * \param[out] result The function puts the handle to the result
5641d5ac70f0Sopenharmony_ci *                    configuration node at the address specified by
5642d5ac70f0Sopenharmony_ci *                    \a result.
5643d5ac70f0Sopenharmony_ci * \return A non-negative value if successful, otherwise a negative error code.
5644d5ac70f0Sopenharmony_ci *
5645d5ac70f0Sopenharmony_ci * If \a config has arguments (defined by a child with id \c \@args),
5646d5ac70f0Sopenharmony_ci * this function replaces any string node beginning with $ with the
5647d5ac70f0Sopenharmony_ci * respective argument value, or the default argument value, or nothing.
5648d5ac70f0Sopenharmony_ci * Furthermore, any functions are evaluated (see #snd_config_evaluate).
5649d5ac70f0Sopenharmony_ci * The resulting copy of \a config is returned in \a result.
5650d5ac70f0Sopenharmony_ci *
5651d5ac70f0Sopenharmony_ci * The new tree is not evaluated (\ref snd_config_evaluate).
5652d5ac70f0Sopenharmony_ci */
5653d5ac70f0Sopenharmony_ciint snd_config_expand_custom(snd_config_t *config, snd_config_t *root,
5654d5ac70f0Sopenharmony_ci			     snd_config_expand_fcn_t fcn, void *private_data,
5655d5ac70f0Sopenharmony_ci			     snd_config_t **result)
5656d5ac70f0Sopenharmony_ci{
5657d5ac70f0Sopenharmony_ci	snd_config_t *res;
5658d5ac70f0Sopenharmony_ci	int err;
5659d5ac70f0Sopenharmony_ci
5660d5ac70f0Sopenharmony_ci	err = snd_config_walk(config, root, &res, _snd_config_expand, fcn, private_data);
5661d5ac70f0Sopenharmony_ci	if (err < 0) {
5662d5ac70f0Sopenharmony_ci		SNDERR("Expand error (walk): %s", snd_strerror(err));
5663d5ac70f0Sopenharmony_ci		return err;
5664d5ac70f0Sopenharmony_ci	}
5665d5ac70f0Sopenharmony_ci	*result = res;
5666d5ac70f0Sopenharmony_ci	return 1;
5667d5ac70f0Sopenharmony_ci}
5668d5ac70f0Sopenharmony_ci
5669d5ac70f0Sopenharmony_ci/**
5670d5ac70f0Sopenharmony_ci * \brief Expands a configuration node, applying arguments and functions.
5671d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration node.
5672d5ac70f0Sopenharmony_ci * \param[in] root Handle to the root configuration node.
5673d5ac70f0Sopenharmony_ci * \param[in] args Arguments string, can be \c NULL.
5674d5ac70f0Sopenharmony_ci * \param[in] private_data Handle to the private data node for functions.
5675d5ac70f0Sopenharmony_ci * \param[out] result The function puts the handle to the result
5676d5ac70f0Sopenharmony_ci *                    configuration node at the address specified by
5677d5ac70f0Sopenharmony_ci *                    \a result.
5678d5ac70f0Sopenharmony_ci * \return A non-negative value if successful, otherwise a negative error code.
5679d5ac70f0Sopenharmony_ci *
5680d5ac70f0Sopenharmony_ci * If \a config has arguments (defined by a child with id \c \@args),
5681d5ac70f0Sopenharmony_ci * this function replaces any string node beginning with $ with the
5682d5ac70f0Sopenharmony_ci * respective argument value, or the default argument value, or nothing.
5683d5ac70f0Sopenharmony_ci * Furthermore, any functions are evaluated (see #snd_config_evaluate).
5684d5ac70f0Sopenharmony_ci * The resulting copy of \a config is returned in \a result.
5685d5ac70f0Sopenharmony_ci */
5686d5ac70f0Sopenharmony_ciint snd_config_expand(snd_config_t *config, snd_config_t *root, const char *args,
5687d5ac70f0Sopenharmony_ci		      snd_config_t *private_data, snd_config_t **result)
5688d5ac70f0Sopenharmony_ci{
5689d5ac70f0Sopenharmony_ci	int err;
5690d5ac70f0Sopenharmony_ci	snd_config_t *defs, *subs = NULL, *res;
5691d5ac70f0Sopenharmony_ci	err = snd_config_search(config, "@args", &defs);
5692d5ac70f0Sopenharmony_ci	if (err < 0) {
5693d5ac70f0Sopenharmony_ci		if (args != NULL) {
5694d5ac70f0Sopenharmony_ci			SNDERR("Unknown parameters %s", args);
5695d5ac70f0Sopenharmony_ci			return -EINVAL;
5696d5ac70f0Sopenharmony_ci		}
5697d5ac70f0Sopenharmony_ci		err = snd_config_copy(&res, config);
5698d5ac70f0Sopenharmony_ci		if (err < 0)
5699d5ac70f0Sopenharmony_ci			return err;
5700d5ac70f0Sopenharmony_ci	} else {
5701d5ac70f0Sopenharmony_ci		err = snd_config_top(&subs);
5702d5ac70f0Sopenharmony_ci		if (err < 0)
5703d5ac70f0Sopenharmony_ci			return err;
5704d5ac70f0Sopenharmony_ci		err = load_defaults(subs, defs);
5705d5ac70f0Sopenharmony_ci		if (err < 0) {
5706d5ac70f0Sopenharmony_ci			SNDERR("Load defaults error: %s", snd_strerror(err));
5707d5ac70f0Sopenharmony_ci			goto _end;
5708d5ac70f0Sopenharmony_ci		}
5709d5ac70f0Sopenharmony_ci		err = parse_args(subs, args, defs);
5710d5ac70f0Sopenharmony_ci		if (err < 0) {
5711d5ac70f0Sopenharmony_ci			SNDERR("Parse arguments error: %s", snd_strerror(err));
5712d5ac70f0Sopenharmony_ci			goto _end;
5713d5ac70f0Sopenharmony_ci		}
5714d5ac70f0Sopenharmony_ci		err = snd_config_evaluate(subs, root, private_data, NULL);
5715d5ac70f0Sopenharmony_ci		if (err < 0) {
5716d5ac70f0Sopenharmony_ci			SNDERR("Args evaluate error: %s", snd_strerror(err));
5717d5ac70f0Sopenharmony_ci			goto _end;
5718d5ac70f0Sopenharmony_ci		}
5719d5ac70f0Sopenharmony_ci		err = snd_config_walk(config, root, &res, _snd_config_expand, _snd_config_expand_vars, subs);
5720d5ac70f0Sopenharmony_ci		if (err < 0) {
5721d5ac70f0Sopenharmony_ci			SNDERR("Expand error (walk): %s", snd_strerror(err));
5722d5ac70f0Sopenharmony_ci			goto _end;
5723d5ac70f0Sopenharmony_ci		}
5724d5ac70f0Sopenharmony_ci	}
5725d5ac70f0Sopenharmony_ci	err = snd_config_evaluate(res, root, private_data, NULL);
5726d5ac70f0Sopenharmony_ci	if (err < 0) {
5727d5ac70f0Sopenharmony_ci		SNDERR("Evaluate error: %s", snd_strerror(err));
5728d5ac70f0Sopenharmony_ci		snd_config_delete(res);
5729d5ac70f0Sopenharmony_ci		goto _end;
5730d5ac70f0Sopenharmony_ci	}
5731d5ac70f0Sopenharmony_ci	*result = res;
5732d5ac70f0Sopenharmony_ci	err = 1;
5733d5ac70f0Sopenharmony_ci _end:
5734d5ac70f0Sopenharmony_ci 	if (subs)
5735d5ac70f0Sopenharmony_ci		snd_config_delete(subs);
5736d5ac70f0Sopenharmony_ci	return err;
5737d5ac70f0Sopenharmony_ci}
5738d5ac70f0Sopenharmony_ci
5739d5ac70f0Sopenharmony_ci/**
5740d5ac70f0Sopenharmony_ci * \brief Searches for a definition in a configuration tree, using
5741d5ac70f0Sopenharmony_ci *        aliases and expanding hooks and arguments.
5742d5ac70f0Sopenharmony_ci * \param[in] config Handle to the configuration (sub)tree to search.
5743d5ac70f0Sopenharmony_ci * \param[in] base Implicit key base, or \c NULL for none.
5744d5ac70f0Sopenharmony_ci * \param[in] name Key suffix, optionally with arguments.
5745d5ac70f0Sopenharmony_ci * \param[out] result The function puts the handle to the expanded found
5746d5ac70f0Sopenharmony_ci *                    node at the address specified by \a result.
5747d5ac70f0Sopenharmony_ci * \return A non-negative value if successful, otherwise a negative error code.
5748d5ac70f0Sopenharmony_ci *
5749d5ac70f0Sopenharmony_ci * This functions searches for a child node of \a config, allowing
5750d5ac70f0Sopenharmony_ci * aliases and expanding hooks, like #snd_config_search_alias_hooks.
5751d5ac70f0Sopenharmony_ci *
5752d5ac70f0Sopenharmony_ci * If \a name contains a colon (:), the rest of the string after the
5753d5ac70f0Sopenharmony_ci * colon contains arguments that are expanded as with
5754d5ac70f0Sopenharmony_ci * #snd_config_expand.
5755d5ac70f0Sopenharmony_ci *
5756d5ac70f0Sopenharmony_ci * In any case, \a result is a new node that must be freed by the
5757d5ac70f0Sopenharmony_ci * caller.
5758d5ac70f0Sopenharmony_ci *
5759d5ac70f0Sopenharmony_ci * \par Errors:
5760d5ac70f0Sopenharmony_ci * <dl>
5761d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>An id in \a key or an alias id does not exist.
5762d5ac70f0Sopenharmony_ci * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is
5763d5ac70f0Sopenharmony_ci *                not a compound node.
5764d5ac70f0Sopenharmony_ci * </dl>
5765d5ac70f0Sopenharmony_ci * Additionally, any errors encountered when parsing the hook
5766d5ac70f0Sopenharmony_ci * definitions or arguments, or returned by (hook) functions.
5767d5ac70f0Sopenharmony_ci */
5768d5ac70f0Sopenharmony_ciint snd_config_search_definition(snd_config_t *config,
5769d5ac70f0Sopenharmony_ci				 const char *base, const char *name,
5770d5ac70f0Sopenharmony_ci				 snd_config_t **result)
5771d5ac70f0Sopenharmony_ci{
5772d5ac70f0Sopenharmony_ci	snd_config_t *conf;
5773d5ac70f0Sopenharmony_ci	char *key;
5774d5ac70f0Sopenharmony_ci	const char *args = strchr(name, ':');
5775d5ac70f0Sopenharmony_ci	int err;
5776d5ac70f0Sopenharmony_ci	if (args) {
5777d5ac70f0Sopenharmony_ci		args++;
5778d5ac70f0Sopenharmony_ci		key = alloca(args - name);
5779d5ac70f0Sopenharmony_ci		memcpy(key, name, args - name - 1);
5780d5ac70f0Sopenharmony_ci		key[args - name - 1] = '\0';
5781d5ac70f0Sopenharmony_ci	} else {
5782d5ac70f0Sopenharmony_ci		key = (char *) name;
5783d5ac70f0Sopenharmony_ci	}
5784d5ac70f0Sopenharmony_ci	/*
5785d5ac70f0Sopenharmony_ci	 *  if key contains dot (.), the implicit base is ignored
5786d5ac70f0Sopenharmony_ci	 *  and the key starts from root given by the 'config' parameter
5787d5ac70f0Sopenharmony_ci	 */
5788d5ac70f0Sopenharmony_ci	snd_config_lock();
5789d5ac70f0Sopenharmony_ci	err = snd_config_search_alias_hooks(config, strchr(key, '.') ? NULL : base, key, &conf);
5790d5ac70f0Sopenharmony_ci	if (err < 0) {
5791d5ac70f0Sopenharmony_ci		snd_config_unlock();
5792d5ac70f0Sopenharmony_ci		return err;
5793d5ac70f0Sopenharmony_ci	}
5794d5ac70f0Sopenharmony_ci	err = snd_config_expand(conf, config, args, NULL, result);
5795d5ac70f0Sopenharmony_ci	snd_config_unlock();
5796d5ac70f0Sopenharmony_ci	return err;
5797d5ac70f0Sopenharmony_ci}
5798d5ac70f0Sopenharmony_ci
5799d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN
5800d5ac70f0Sopenharmony_civoid snd_config_set_hop(snd_config_t *conf, int hop)
5801d5ac70f0Sopenharmony_ci{
5802d5ac70f0Sopenharmony_ci	conf->hop = hop;
5803d5ac70f0Sopenharmony_ci}
5804d5ac70f0Sopenharmony_ci
5805d5ac70f0Sopenharmony_ciint snd_config_check_hop(snd_config_t *conf)
5806d5ac70f0Sopenharmony_ci{
5807d5ac70f0Sopenharmony_ci	if (conf) {
5808d5ac70f0Sopenharmony_ci		if (conf->hop >= SND_CONF_MAX_HOPS) {
5809d5ac70f0Sopenharmony_ci			SYSERR("Too many definition levels (looped?)\n");
5810d5ac70f0Sopenharmony_ci			return -EINVAL;
5811d5ac70f0Sopenharmony_ci		}
5812d5ac70f0Sopenharmony_ci		return conf->hop;
5813d5ac70f0Sopenharmony_ci	}
5814d5ac70f0Sopenharmony_ci	return 0;
5815d5ac70f0Sopenharmony_ci}
5816d5ac70f0Sopenharmony_ci#endif
5817d5ac70f0Sopenharmony_ci
5818d5ac70f0Sopenharmony_ci#if 0
5819d5ac70f0Sopenharmony_ci/* Not strictly needed, but useful to check for memory leaks */
5820d5ac70f0Sopenharmony_civoid _snd_config_end(void) __attribute__ ((destructor));
5821d5ac70f0Sopenharmony_ci
5822d5ac70f0Sopenharmony_cistatic void _snd_config_end(void)
5823d5ac70f0Sopenharmony_ci{
5824d5ac70f0Sopenharmony_ci	int k;
5825d5ac70f0Sopenharmony_ci	if (snd_config)
5826d5ac70f0Sopenharmony_ci		snd_config_delete(snd_config);
5827d5ac70f0Sopenharmony_ci	snd_config = 0;
5828d5ac70f0Sopenharmony_ci	for (k = 0; k < files_info_count; ++k)
5829d5ac70f0Sopenharmony_ci		free(files_info[k].name);
5830d5ac70f0Sopenharmony_ci	free(files_info);
5831d5ac70f0Sopenharmony_ci	files_info = NULL;
5832d5ac70f0Sopenharmony_ci	files_info_count = 0;
5833d5ac70f0Sopenharmony_ci}
5834d5ac70f0Sopenharmony_ci#endif
5835d5ac70f0Sopenharmony_ci
5836d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN
5837d5ac70f0Sopenharmony_cisize_t page_size(void)
5838d5ac70f0Sopenharmony_ci{
5839d5ac70f0Sopenharmony_ci	long s = sysconf(_SC_PAGE_SIZE);
5840d5ac70f0Sopenharmony_ci	assert(s > 0);
5841d5ac70f0Sopenharmony_ci	return s;
5842d5ac70f0Sopenharmony_ci}
5843d5ac70f0Sopenharmony_ci
5844d5ac70f0Sopenharmony_cisize_t page_align(size_t size)
5845d5ac70f0Sopenharmony_ci{
5846d5ac70f0Sopenharmony_ci	size_t r;
5847d5ac70f0Sopenharmony_ci	long psz = page_size();
5848d5ac70f0Sopenharmony_ci	r = size % psz;
5849d5ac70f0Sopenharmony_ci	if (r)
5850d5ac70f0Sopenharmony_ci		return size + psz - r;
5851d5ac70f0Sopenharmony_ci	return size;
5852d5ac70f0Sopenharmony_ci}
5853d5ac70f0Sopenharmony_ci
5854d5ac70f0Sopenharmony_cisize_t page_ptr(size_t object_offset, size_t object_size, size_t *offset, size_t *mmap_offset)
5855d5ac70f0Sopenharmony_ci{
5856d5ac70f0Sopenharmony_ci	size_t r;
5857d5ac70f0Sopenharmony_ci	long psz = page_size();
5858d5ac70f0Sopenharmony_ci	assert(offset);
5859d5ac70f0Sopenharmony_ci	assert(mmap_offset);
5860d5ac70f0Sopenharmony_ci	*mmap_offset = object_offset;
5861d5ac70f0Sopenharmony_ci	object_offset %= psz;
5862d5ac70f0Sopenharmony_ci	*mmap_offset -= object_offset;
5863d5ac70f0Sopenharmony_ci	object_size += object_offset;
5864d5ac70f0Sopenharmony_ci	r = object_size % psz;
5865d5ac70f0Sopenharmony_ci	if (r)
5866d5ac70f0Sopenharmony_ci		r = object_size + psz - r;
5867d5ac70f0Sopenharmony_ci	else
5868d5ac70f0Sopenharmony_ci		r = object_size;
5869d5ac70f0Sopenharmony_ci	*offset = object_offset;
5870d5ac70f0Sopenharmony_ci	return r;
5871d5ac70f0Sopenharmony_ci}
5872d5ac70f0Sopenharmony_ci#endif /* DOC_HIDDEN */
5873